-What: /sys/block/rssd*/registers
-Date: March 2012
-KernelVersion: 3.3
-Contact: Asai Thambi S P <asamymuthupa@micron.com>
-Description: This is a read-only file. Dumps below driver information and
- hardware registers.
- - S ACTive
- - Command Issue
- - Completed
- - PORT IRQ STAT
- - HOST IRQ STAT
- - Allocated
- - Commands in Q
-
What: /sys/block/rssd*/status
Date: April 2012
KernelVersion: 3.4
Contact: Asai Thambi S P <asamymuthupa@micron.com>
Description: This is a read-only file. Indicates the status of the device.
-
-What: /sys/block/rssd*/flags
-Date: May 2012
-KernelVersion: 3.5
-Contact: Asai Thambi S P <asamymuthupa@micron.com>
-Description: This is a read-only file. Dumps the flags in port and driver
- data structure
Contact: linux-mtd@lists.infradead.org
Description:
This allows the user to examine and adjust the criteria by which
- mtd returns -EUCLEAN from mtd_read(). If the maximum number of
- bit errors that were corrected on any single region comprising
- an ecc step (as reported by the driver) equals or exceeds this
- value, -EUCLEAN is returned. Otherwise, absent an error, 0 is
- returned. Higher layers (e.g., UBI) use this return code as an
- indication that an erase block may be degrading and should be
- scrutinized as a candidate for being marked as bad.
+ mtd returns -EUCLEAN from mtd_read() and mtd_read_oob(). If the
+ maximum number of bit errors that were corrected on any single
+ region comprising an ecc step (as reported by the driver) equals
+ or exceeds this value, -EUCLEAN is returned. Otherwise, absent
+ an error, 0 is returned. Higher layers (e.g., UBI) use this
+ return code as an indication that an erase block may be
+ degrading and should be scrutinized as a candidate for being
+ marked as bad.
The initial value may be specified by the flash device driver.
If not, then the default value is ecc_strength.
block degradation, but high enough to avoid the consequences of
a persistent return value of -EUCLEAN on devices where sticky
bitflips occur. Note that if bitflip_threshold exceeds
- ecc_strength, -EUCLEAN is never returned by mtd_read().
+ ecc_strength, -EUCLEAN is never returned by the read operations.
Conversely, if bitflip_threshold is zero, -EUCLEAN is always
returned, absent a hard error.
from RGB to Y'CbCr color space.
</entry>
</row>
- <row id = "v4l2-jpeg-chroma-subsampling">
+ <row>
<entrytbl spanname="descr" cols="2">
<tbody valign="top">
<row>
processing controls. These controls are described in <xref
linkend="image-process-controls" />.</entry>
</row>
- <row>
- <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
- <entry>0x9d0000</entry>
- <entry>The class containing JPEG compression controls.
-These controls are described in <xref
- linkend="jpeg-controls" />.</entry>
- </row>
</tbody>
</tgroup>
</table>
Construction Parameters
=======================
- <version> <dev> <hash_dev> <hash_start>
+ <version> <dev> <hash_dev>
<data_block_size> <hash_block_size>
<num_data_blocks> <hash_start_block>
<algorithm> <digest> <salt>
<version>
- This is the version number of the on-disk format.
+ This is the type of the on-disk hash format.
0 is the original format used in the Chromium OS.
- The salt is appended when hashing, digests are stored continuously and
- the rest of the block is padded with zeros.
+ The salt is appended when hashing, digests are stored continuously and
+ the rest of the block is padded with zeros.
1 is the current format that should be used for new devices.
- The salt is prepended when hashing and each digest is
- padded with zeros to the power of two.
+ The salt is prepended when hashing and each digest is
+ padded with zeros to the power of two.
<dev>
- This is the device containing the data the integrity of which needs to be
+ This is the device containing data, the integrity of which needs to be
checked. It may be specified as a path, like /dev/sdaX, or a device number,
<major>:<minor>.
<hash_dev>
- This is the device that that supplies the hash tree data. It may be
+ This is the device that supplies the hash tree data. It may be
specified similarly to the device path and may be the same device. If the
- same device is used, the hash_start should be outside of the dm-verity
- configured device size.
+ same device is used, the hash_start should be outside the configured
+ dm-verity device.
<data_block_size>
- The block size on a data device. Each block corresponds to one digest on
- the hash device.
+ The block size on a data device in bytes.
+ Each block corresponds to one digest on the hash device.
<hash_block_size>
- The size of a hash block.
+ The size of a hash block in bytes.
<num_data_blocks>
The number of data blocks on the data device. Additional blocks are
Theory of operation
===================
-dm-verity is meant to be setup as part of a verified boot path. This
+dm-verity is meant to be set up as part of a verified boot path. This
may be anything ranging from a boot using tboot or trustedgrub to just
booting from a known-good device (like a USB drive or CD).
has been authenticated in some way (cryptographic signatures, etc).
After instantiation, all hashes will be verified on-demand during
disk access. If they cannot be verified up to the root node of the
-tree, the root hash, then the I/O will fail. This should identify
+tree, the root hash, then the I/O will fail. This should detect
tampering with any data on the device and the hash data.
Cryptographic hashes are used to assert the integrity of the device on a
-per-block basis. This allows for a lightweight hash computation on first read
-into the page cache. Block hashes are stored linearly-aligned to the nearest
-block the size of a page.
+per-block basis. This allows for a lightweight hash computation on first read
+into the page cache. Block hashes are stored linearly, aligned to the nearest
+block size.
Hash Tree
---------
Each node in the tree is a cryptographic hash. If it is a leaf node, the hash
-is of some block data on disk. If it is an intermediary node, then the hash is
-of a number of child nodes.
+of some data block on disk is calculated. If it is an intermediary node,
+the hash of a number of child nodes is calculated.
Each entry in the tree is a collection of neighboring nodes that fit in one
block. The number is determined based on block_size and the size of the
On-disk format
==============
-Below is the recommended on-disk format. The verity kernel code does not
-read the on-disk header. It only reads the hash blocks which directly
-follow the header. It is expected that a user-space tool will verify the
-integrity of the verity_header and then call dmsetup with the correct
-parameters. Alternatively, the header can be omitted and the dmsetup
-parameters can be passed via the kernel command-line in a rooted chain
-of trust where the command-line is verified.
+The verity kernel code does not read the verity metadata on-disk header.
+It only reads the hash blocks which directly follow the header.
+It is expected that a user-space tool will verify the integrity of the
+verity header.
-The on-disk format is especially useful in cases where the hash blocks
-are on a separate partition. The magic number allows easy identification
-of the partition contents. Alternatively, the hash blocks can be stored
-in the same partition as the data to be verified. In such a configuration
-the filesystem on the partition would be sized a little smaller than
-the full-partition, leaving room for the hash blocks.
-
-struct superblock {
- uint8_t signature[8]
- "verity\0\0";
-
- uint8_t version;
- 1 - current format
-
- uint8_t data_block_bits;
- log2(data block size)
-
- uint8_t hash_block_bits;
- log2(hash block size)
-
- uint8_t pad1[1];
- zero padding
-
- uint16_t salt_size;
- big-endian salt size
-
- uint8_t pad2[2];
- zero padding
-
- uint32_t data_blocks_hi;
- big-endian high 32 bits of the 64-bit number of data blocks
-
- uint32_t data_blocks_lo;
- big-endian low 32 bits of the 64-bit number of data blocks
-
- uint8_t algorithm[16];
- cryptographic algorithm
-
- uint8_t salt[384];
- salt (the salt size is specified above)
-
- uint8_t pad3[88];
- zero padding to 512-byte boundary
-}
+Alternatively, the header can be omitted and the dmsetup parameters can
+be passed via the kernel command-line in a rooted chain of trust where
+the command-line is verified.
Directly following the header (and with sector number padded to the next hash
block boundary) are the hash blocks which are stored a depth at a time
(starting from the root), sorted in order of increasing index.
+The full specification of kernel parameters and on-disk metadata format
+is available at the cryptsetup project's wiki page
+ http://code.google.com/p/cryptsetup/wiki/DMVerity
+
Status
======
V (for Valid) is returned if every check performed so far was valid.
Example
=======
-
-Setup a device:
- dmsetup create vroot --table \
- "0 2097152 "\
- "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
+Set up a device:
+ # dmsetup create vroot --readonly --table \
+ "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\
"4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
"1234000000000000000000000000000000000000000000000000000000000000"
A command line tool veritysetup is available to compute or verify
-the hash tree or activate the kernel driver. This is available from
-the LVM2 upstream repository and may be supplied as a package called
-device-mapper-verity-tools:
- git://sources.redhat.com/git/lvm2
- http://sourceware.org/git/?p=lvm2.git
- http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
-
-veritysetup -a vroot /dev/sda1 /dev/sda2 \
- 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+the hash tree or activate the kernel device. This is available from
+the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
+(as a libcryptsetup extension).
+
+Create hash on the device:
+ # veritysetup format /dev/sda1 /dev/sda2
+ ...
+ Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+
+Activate the device:
+ # veritysetup create vroot /dev/sda1 /dev/sda2 \
+ 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
Required properties:
- compatible : "fsl,mma8450".
+- reg: the I2C address of MMA8450
Example:
ecspi@70010000 { /* ECSPI1 */
fsl,spi-num-chipselects = <2>;
- cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
- <&gpio3 25 0>; /* GPIO4_25 */
+ cs-gpios = <&gpio4 24 0>, /* GPIO4_24 */
+ <&gpio4 25 0>; /* GPIO4_25 */
status = "okay";
pmic: mc13892@0 {
device need to be present. The definition for each of these nodes is defined
using the standard binding for regulators found at
Documentation/devicetree/bindings/regulator/regulator.txt.
+ The regulator is matched with the regulator-compatible.
- The valid names for regulators are:
+ The valid regulator-compatible values are:
tps65910: vrtc, vio, vdd1, vdd2, vdd3, vdig1, vdig2, vpll, vdac, vaux1,
vaux2, vaux33, vmmc
tps65911: vrtc, vio, vdd1, vdd3, vddctrl, ldo1, ldo2, ldo3, ldo4, ldo5,
ldo6, ldo7, ldo8
+- xxx-supply: Input voltage supply regulator.
+ These entries are require if regulators are enabled for a device. Missing of these
+ properties can cause the regulator registration fails.
+ If some of input supply is powered through battery or always-on supply then
+ also it is require to have these parameters with proper node handle of always
+ on power supply.
+ tps65910:
+ vcc1-supply: VDD1 input.
+ vcc2-supply: VDD2 input.
+ vcc3-supply: VAUX33 and VMMC input.
+ vcc4-supply: VAUX1 and VAUX2 input.
+ vcc5-supply: VPLL and VDAC input.
+ vcc6-supply: VDIG1 and VDIG2 input.
+ vcc7-supply: VRTC input.
+ vccio-supply: VIO input.
+ tps65911:
+ vcc1-supply: VDD1 input.
+ vcc2-supply: VDD2 input.
+ vcc3-supply: LDO6, LDO7 and LDO8 input.
+ vcc4-supply: LDO5 input.
+ vcc5-supply: LDO3 and LDO4 input.
+ vcc6-supply: LDO1 and LDO2 input.
+ vcc7-supply: VRTC input.
+ vccio-supply: VIO input.
+
Optional properties:
- ti,vmbch-threshold: (tps65911) main battery charged threshold
comparator. (see VMBCH_VSEL in TPS65910 datasheet)
- ti,vmbch2-threshold: (tps65911) main battery discharged threshold
comparator. (see VMBCH_VSEL in TPS65910 datasheet)
+- ti,en-ck32k-xtal: enable external 32-kHz crystal oscillator (see CK32K_CTRL
+ in TPS6591X datasheet)
- ti,en-gpio-sleep: enable sleep control for gpios
There should be 9 entries here, one for each gpio.
ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>;
+ vcc1-supply = <®_parent>;
+ vcc2-supply = <&some_reg>;
+ vcc3-supply = <...>;
+ vcc4-supply = <...>;
+ vcc5-supply = <...>;
+ vcc6-supply = <...>;
+ vcc7-supply = <...>;
+ vccio-supply = <...>;
+
regulators {
- vdd1_reg: vdd1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdd1_reg: regulator@0 {
+ regulator-compatible = "vdd1";
+ reg = <0>;
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <0>;
};
- vdd2_reg: vdd2 {
+ vdd2_reg: regulator@1 {
+ regulator-compatible = "vdd2";
+ reg = <1>;
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <4>;
};
- vddctrl_reg: vddctrl {
+ vddctrl_reg: regulator@2 {
+ regulator-compatible = "vddctrl";
+ reg = <2>;
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1400000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <0>;
};
- vio_reg: vio {
+ vio_reg: regulator@3 {
+ regulator-compatible = "vio";
+ reg = <3>;
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <1>;
};
- ldo1_reg: ldo1 {
+ ldo1_reg: regulator@4 {
+ regulator-compatible = "ldo1";
+ reg = <4>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
- ldo2_reg: ldo2 {
+ ldo2_reg: regulator@5 {
+ regulator-compatible = "ldo2";
+ reg = <5>;
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
ti,regulator-ext-sleep-control = <0>;
};
- ldo3_reg: ldo3 {
+ ldo3_reg: regulator@6 {
+ regulator-compatible = "ldo3";
+ reg = <6>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
- ldo4_reg: ldo4 {
+ ldo4_reg: regulator@7 {
+ regulator-compatible = "ldo4";
+ reg = <7>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
ti,regulator-ext-sleep-control = <0>;
};
- ldo5_reg: ldo5 {
+ ldo5_reg: regulator@8 {
+ regulator-compatible = "ldo5";
+ reg = <8>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
- ldo6_reg: ldo6 {
+ ldo6_reg: regulator@9 {
+ regulator-compatible = "ldo6";
+ reg = <9>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
ti,regulator-ext-sleep-control = <0>;
};
- ldo7_reg: ldo7 {
+ ldo7_reg: regulator@10 {
+ regulator-compatible = "ldo7";
+ reg = <10>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <1>;
};
- ldo8_reg: ldo8 {
+ ldo8_reg: regulator@11 {
+ regulator-compatible = "ldo8";
+ reg = <11>;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
compatible = "fsl,imx51-esdhc";
reg = <0x70008000 0x4000>;
interrupts = <2>;
- cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */
- wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */
+ cd-gpios = <&gpio1 6 0>; /* GPIO1_6 */
+ wp-gpios = <&gpio1 5 0>; /* GPIO1_5 */
};
reg = <0x83fec000 0x4000>;
interrupts = <87>;
phy-mode = "mii";
- phy-reset-gpios = <&gpio1 14 0>; /* GPIO2_14 */
+ phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */
local-mac-address = [00 04 9F 01 1B B9];
};
If this property is missing, the default assumed is Active low.
- gpio-open-drain: GPIO is open drain type.
If this property is missing then default assumption is false.
+-vin-supply: Input supply name.
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
enable-active-high;
regulator-boot-on;
gpio-open-drain;
+ vin-supply = <&parent_reg>;
};
- regulator-always-on: boolean, regulator should never be disabled
- regulator-boot-on: bootloader/firmware enabled regulator
- <name>-supply: phandle to the parent supply/regulator node
+- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
+- regulator-compatible: If a regulator chip contains multiple
+ regulators, and if the chip's binding contains a child node that
+ describes each regulator, then this property indicates which regulator
+ this child node is intended to configure.
Example:
--- /dev/null
+TPS65217 family of regulators
+
+Required properties:
+- compatible: "ti,tps65217"
+- reg: I2C slave address
+- regulators: list of regulators provided by this controller, must be named
+ after their hardware counterparts: dcdc[1-3] and ldo[1-4]
+- regulators: This is the list of child nodes that specify the regulator
+ initialization data for defined regulators. Not all regulators for the given
+ device need to be present. The definition for each of these nodes is defined
+ using the standard binding for regulators found at
+ Documentation/devicetree/bindings/regulator/regulator.txt.
+
+ The valid names for regulators are:
+ tps65217: dcdc1, dcdc2, dcdc3, ldo1, ldo2, ldo3 and ldo4
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+ tps: tps@24 {
+ compatible = "ti,tps65217";
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dcdc1_reg: regulator@0 {
+ reg = <0>;
+ regulator-compatible = "dcdc1";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc2_reg: regulator@1 {
+ reg = <1>;
+ regulator-compatible = "dcdc2";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc3_reg: regulator@2 {
+ reg = <2>;
+ regulator-compatible = "dcdc3";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: regulator@3 {
+ reg = <3>;
+ regulator-compatible = "ldo1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2_reg: regulator@4 {
+ reg = <4>;
+ regulator-compatible = "ldo2";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo3_reg: regulator@5 {
+ reg = <5>;
+ regulator-compatible = "ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo4_reg: regulator@6 {
+ reg = <6>;
+ regulator-compatible = "ldo4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
- interrupts: the interrupt outputs of the controller
- #gpio-cells: number of cells to describe a GPIO
- gpio-controller: mark the device as a GPIO controller
-- regulators: list of regulators provided by this controller, must be named
- after their hardware counterparts: sm[0-2], ldo[0-9] and ldo_rtc
+- regulators: list of regulators provided by this controller, must have
+ property "regulator-compatible" to match their hardware counterparts:
+ sm[0-2], ldo[0-9] and ldo_rtc
+- sm0-supply: The input supply for the SM0.
+- sm1-supply: The input supply for the SM1.
+- sm2-supply: The input supply for the SM2.
+- vinldo01-supply: The input supply for the LDO1 and LDO2
+- vinldo23-supply: The input supply for the LDO2 and LDO3
+- vinldo4-supply: The input supply for the LDO4
+- vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8
+- vinldo9-supply: The input supply for the LDO9
Each regulator is defined using the standard binding for regulators.
#gpio-cells = <2>;
gpio-controller;
+ sm0-supply = <&some_reg>;
+ sm1-supply = <&some_reg>;
+ sm2-supply = <&some_reg>;
+ vinldo01-supply = <...>;
+ vinldo23-supply = <...>;
+ vinldo4-supply = <...>;
+ vinldo678-supply = <...>;
+ vinldo9-supply = <...>;
+
regulators {
- sm0_reg: sm0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sm0_reg: regulator@0 {
+ reg = <0>;
+ regulator-compatible = "sm0";
regulator-min-microvolt = < 725000>;
regulator-max-microvolt = <1500000>;
regulator-boot-on;
regulator-always-on;
};
- sm1_reg: sm1 {
+ sm1_reg: regulator@1 {
+ reg = <1>;
+ regulator-compatible = "sm1";
regulator-min-microvolt = < 725000>;
regulator-max-microvolt = <1500000>;
regulator-boot-on;
regulator-always-on;
};
- sm2_reg: sm2 {
+ sm2_reg: regulator@2 {
+ reg = <2>;
+ regulator-compatible = "sm2";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <4550000>;
regulator-boot-on;
regulator-always-on;
};
- ldo0_reg: ldo0 {
+ ldo0_reg: regulator@3 {
+ reg = <3>;
+ regulator-compatible = "ldo0";
regulator-name = "PCIE CLK";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
- ldo1_reg: ldo1 {
+ ldo1_reg: regulator@4 {
+ reg = <4>;
+ regulator-compatible = "ldo1";
regulator-min-microvolt = < 725000>;
regulator-max-microvolt = <1500000>;
};
- ldo2_reg: ldo2 {
+ ldo2_reg: regulator@5 {
+ reg = <5>;
+ regulator-compatible = "ldo2";
regulator-min-microvolt = < 725000>;
regulator-max-microvolt = <1500000>;
};
- ldo3_reg: ldo3 {
+ ldo3_reg: regulator@6 {
+ reg = <6>;
+ regulator-compatible = "ldo3";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- ldo4_reg: ldo4 {
+ ldo4_reg: regulator@7 {
+ reg = <7>;
+ regulator-compatible = "ldo4";
regulator-min-microvolt = <1700000>;
regulator-max-microvolt = <2475000>;
};
- ldo5_reg: ldo5 {
+ ldo5_reg: regulator@8 {
+ reg = <8>;
+ regulator-compatible = "ldo5";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- ldo6_reg: ldo6 {
+ ldo6_reg: regulator@9 {
+ reg = <9>;
+ regulator-compatible = "ldo6";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- ldo7_reg: ldo7 {
+ ldo7_reg: regulator@10 {
+ reg = <10>;
+ regulator-compatible = "ldo7";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- ldo8_reg: ldo8 {
+ ldo8_reg: regulator@11 {
+ reg = <11>;
+ regulator-compatible = "ldo8";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- ldo9_reg: ldo9 {
+ ldo9_reg: regulator@12 {
+ reg = <12>;
+ regulator-compatible = "ldo9";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <3300000>;
};
- "ti,twl6030-vusb" for VUSB LDO
- "ti,twl6030-v1v8" for V1V8 LDO
- "ti,twl6030-v2v1" for V2V1 LDO
- - "ti,twl6030-clk32kg" for CLK32KG RESOURCE
- "ti,twl6030-vdd1" for VDD1 SMPS
- "ti,twl6030-vdd2" for VDD2 SMPS
- "ti,twl6030-vdd3" for VDD3 SMPS
reg = <0x70010000 0x4000>;
interrupts = <36>;
fsl,spi-num-chipselects = <2>;
- cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
- <&gpio3 25 0>; /* GPIO4_25 */
+ cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */
+ <&gpio3 25 0>; /* GPIO3_25 */
};
This isn't an exhaustive list, but you should add new prefixes to it before
using them to avoid name-space collisions.
+ad Avionic Design GmbH
adi Analog Devices, Inc.
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
apm Applied Micro Circuits Corporation (APM)
--- /dev/null
+The execve system call can grant a newly-started program privileges that
+its parent did not have. The most obvious examples are setuid/setgid
+programs and file capabilities. To prevent the parent program from
+gaining these privileges as well, the kernel and user code must be
+careful to prevent the parent from doing anything that could subvert the
+child. For example:
+
+ - The dynamic loader handles LD_* environment variables differently if
+ a program is setuid.
+
+ - chroot is disallowed to unprivileged processes, since it would allow
+ /etc/passwd to be replaced from the point of view of a process that
+ inherited chroot.
+
+ - The exec code has special handling for ptrace.
+
+These are all ad-hoc fixes. The no_new_privs bit (since Linux 3.5) is a
+new, generic mechanism to make it safe for a process to modify its
+execution environment in a manner that persists across execve. Any task
+can set no_new_privs. Once the bit is set, it is inherited across fork,
+clone, and execve and cannot be unset. With no_new_privs set, execve
+promises not to grant the privilege to do anything that could not have
+been done without the execve call. For example, the setuid and setgid
+bits will no longer change the uid or gid; file capabilities will not
+add to the permitted set, and LSMs will not relax constraints after
+execve.
+
+To set no_new_privs, use prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0).
+
+Be careful, though: LSMs might also not tighten constraints on exec
+in no_new_privs mode. (This means that setting up a general-purpose
+service launcher to set no_new_privs before execing daemons may
+interfere with LSM-based sandboxing.)
+
+Note that no_new_privs does not prevent privilege changes that do not
+involve execve. An appropriately privileged task can still call
+setuid(2) and receive SCM_RIGHTS datagrams.
+
+There are two main use cases for no_new_privs so far:
+
+ - Filters installed for the seccomp mode 2 sandbox persist across
+ execve and can change the behavior of newly-executed programs.
+ Unprivileged users are therefore only allowed to install such filters
+ if no_new_privs is set.
+
+ - By itself, no_new_privs can be used to reduce the attack surface
+ available to an unprivileged user. If everything running with a
+ given uid has no_new_privs set, then that uid will be unable to
+ escalate its privileges by directly attacking setuid, setgid, and
+ fcap-using binaries; it will need to compromise something without the
+ no_new_privs bit set first.
+
+In the future, other potentially dangerous kernel features could become
+available to unprivileged tasks if no_new_privs is set. In principle,
+several options to unshare(2) and clone(2) would be safe when
+no_new_privs is set, and no_new_privs + chroot is considerable less
+dangerous than chroot by itself.
PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
into the hash PTE second double word).
+4.75 KVM_IRQFD
+
+Capability: KVM_CAP_IRQFD
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_irqfd (in)
+Returns: 0 on success, -1 on error
+
+Allows setting an eventfd to directly trigger a guest interrupt.
+kvm_irqfd.fd specifies the file descriptor to use as the eventfd and
+kvm_irqfd.gsi specifies the irqchip pin toggled by this event. When
+an event is tiggered on the eventfd, an interrupt is injected into
+the guest using the specified gsi pin. The irqfd is removed using
+the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
+and kvm_irqfd.gsi.
+
+
5. The kvm_run structure
------------------------
L: coreteam@netfilter.org
W: http://www.netfilter.org/
W: http://www.iptables.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-2.6.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next-2.6.git
+T: git git://1984.lsi.us.es/nf
+T: git git://1984.lsi.us.es/nf-next
S: Supported
F: include/linux/netfilter*
F: include/linux/netfilter/
L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/*omap*/*pm*
+F: drivers/cpufreq/omap-cpufreq.c
OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT
M: Rajendra Nayak <rnayak@ti.com>
M: Peter Zijlstra <peterz@infradead.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
S: Maintained
-F: kernel/sched*
+F: kernel/sched/
F: include/linux/sched.h
SCORE ARCHITECTURE
VERSION = 3
PATCHLEVEL = 5
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc7
NAME = Saber-toothed Squirrel
# *DOCUMENTATION*
// DB8500_REGULATOR_VAPE
db8500_vape_reg: db8500_vape {
+ regulator-compatible = "db8500_vape";
regulator-name = "db8500-vape";
regulator-always-on;
};
// DB8500_REGULATOR_VARM
db8500_varm_reg: db8500_varm {
+ regulator-compatible = "db8500_varm";
regulator-name = "db8500-varm";
};
// DB8500_REGULATOR_VMODEM
db8500_vmodem_reg: db8500_vmodem {
+ regulator-compatible = "db8500_vmodem";
regulator-name = "db8500-vmodem";
};
// DB8500_REGULATOR_VPLL
db8500_vpll_reg: db8500_vpll {
+ regulator-compatible = "db8500_vpll";
regulator-name = "db8500-vpll";
};
// DB8500_REGULATOR_VSMPS1
db8500_vsmps1_reg: db8500_vsmps1 {
+ regulator-compatible = "db8500_vsmps1";
regulator-name = "db8500-vsmps1";
};
// DB8500_REGULATOR_VSMPS2
db8500_vsmps2_reg: db8500_vsmps2 {
+ regulator-compatible = "db8500_vsmps2";
regulator-name = "db8500-vsmps2";
};
// DB8500_REGULATOR_VSMPS3
db8500_vsmps3_reg: db8500_vsmps3 {
+ regulator-compatible = "db8500_vsmps3";
regulator-name = "db8500-vsmps3";
};
// DB8500_REGULATOR_VRF1
db8500_vrf1_reg: db8500_vrf1 {
+ regulator-compatible = "db8500_vrf1";
regulator-name = "db8500-vrf1";
};
// DB8500_REGULATOR_SWITCH_SVAMMDSP
db8500_sva_mmdsp_reg: db8500_sva_mmdsp {
+ regulator-compatible = "db8500_sva_mmdsp";
regulator-name = "db8500-sva-mmdsp";
};
// DB8500_REGULATOR_SWITCH_SVAMMDSPRET
db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret {
+ regulator-compatible = "db8500_sva_mmdsp_ret";
regulator-name = "db8500-sva-mmdsp-ret";
};
// DB8500_REGULATOR_SWITCH_SVAPIPE
db8500_sva_pipe_reg: db8500_sva_pipe {
+ regulator-compatible = "db8500_sva_pipe";
regulator-name = "db8500_sva_pipe";
};
// DB8500_REGULATOR_SWITCH_SIAMMDSP
db8500_sia_mmdsp_reg: db8500_sia_mmdsp {
+ regulator-compatible = "db8500_sia_mmdsp";
regulator-name = "db8500_sia_mmdsp";
};
// DB8500_REGULATOR_SWITCH_SIAPIPE
db8500_sia_pipe_reg: db8500_sia_pipe {
+ regulator-compatible = "db8500_sia_pipe";
regulator-name = "db8500-sia-pipe";
};
// DB8500_REGULATOR_SWITCH_SGA
db8500_sga_reg: db8500_sga {
+ regulator-compatible = "db8500_sga";
regulator-name = "db8500-sga";
vin-supply = <&db8500_vape_reg>;
};
// DB8500_REGULATOR_SWITCH_B2R2_MCDE
db8500_b2r2_mcde_reg: db8500_b2r2_mcde {
+ regulator-compatible = "db8500_b2r2_mcde";
regulator-name = "db8500-b2r2-mcde";
vin-supply = <&db8500_vape_reg>;
};
// DB8500_REGULATOR_SWITCH_ESRAM12
db8500_esram12_reg: db8500_esram12 {
+ regulator-compatible = "db8500_esram12";
regulator-name = "db8500-esram12";
};
// DB8500_REGULATOR_SWITCH_ESRAM12RET
db8500_esram12_ret_reg: db8500_esram12_ret {
+ regulator-compatible = "db8500_esram12_ret";
regulator-name = "db8500-esram12-ret";
};
// DB8500_REGULATOR_SWITCH_ESRAM34
db8500_esram34_reg: db8500_esram34 {
+ regulator-compatible = "db8500_esram34";
regulator-name = "db8500-esram34";
};
// DB8500_REGULATOR_SWITCH_ESRAM34RET
db8500_esram34_ret_reg: db8500_esram34_ret {
+ regulator-compatible = "db8500_esram34_ret";
regulator-name = "db8500-esram34-ret";
};
};
// supplies to the display/camera
ab8500_ldo_aux1_reg: ab8500_ldo_aux1 {
+ regulator-compatible = "ab8500_ldo_aux1";
regulator-name = "V-DISPLAY";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <2900000>;
// supplies to the on-board eMMC
ab8500_ldo_aux2_reg: ab8500_ldo_aux2 {
+ regulator-compatible = "ab8500_ldo_aux2";
regulator-name = "V-eMMC1";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <3300000>;
// supply for VAUX3; SDcard slots
ab8500_ldo_aux3_reg: ab8500_ldo_aux3 {
+ regulator-compatible = "ab8500_ldo_aux3";
regulator-name = "V-MMC-SD";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <3300000>;
// supply for v-intcore12; VINTCORE12 LDO
ab8500_ldo_initcore_reg: ab8500_ldo_initcore {
+ regulator-compatible = "ab8500_ldo_initcore";
regulator-name = "V-INTCORE";
};
// supply for tvout; gpadc; TVOUT LDO
ab8500_ldo_tvout_reg: ab8500_ldo_tvout {
+ regulator-compatible = "ab8500_ldo_tvout";
regulator-name = "V-TVOUT";
};
// supply for ab8500-usb; USB LDO
ab8500_ldo_usb_reg: ab8500_ldo_usb {
+ regulator-compatible = "ab8500_ldo_usb";
regulator-name = "dummy";
};
// supply for ab8500-vaudio; VAUDIO LDO
ab8500_ldo_audio_reg: ab8500_ldo_audio {
+ regulator-compatible = "ab8500_ldo_audio";
regulator-name = "V-AUD";
};
// supply for v-anamic1 VAMic1-LDO
ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 {
+ regulator-compatible = "ab8500_ldo_anamic1";
regulator-name = "V-AMIC1";
};
// supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1
ab8500_ldo_amamic2_reg: ab8500_ldo_amamic2 {
+ regulator-compatible = "ab8500_ldo_amamic2";
regulator-name = "V-AMIC2";
};
// supply for v-dmic; VDMIC LDO
ab8500_ldo_dmic_reg: ab8500_ldo_dmic {
+ regulator-compatible = "ab8500_ldo_dmic";
regulator-name = "V-DMIC";
};
// supply for U8500 CSI/DSI; VANA LDO
ab8500_ldo_ana_reg: ab8500_ldo_ana {
+ regulator-compatible = "ab8500_ldo_ana";
regulator-name = "V-CSI/DSI";
};
};
CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_LIBUSUAL=y
#define ATOMIC64_INIT(i) { (i) }
-static inline u64 atomic64_read(atomic64_t *v)
+static inline u64 atomic64_read(const atomic64_t *v)
{
u64 result;
#ifndef __ASSEMBLY__
#ifdef CONFIG_CPU_USE_DOMAINS
-#define set_domain(x) \
- do { \
- __asm__ __volatile__( \
- "mcr p15, 0, %0, c3, c0 @ set domain" \
- : : "r" (x)); \
- isb(); \
- } while (0)
+static inline void set_domain(unsigned val)
+{
+ asm volatile(
+ "mcr p15, 0, %0, c3, c0 @ set domain"
+ : : "r" (val));
+ isb();
+}
#define modify_domain(dom,type) \
do { \
} while (0)
#else
-#define set_domain(x) do { } while (0)
-#define modify_domain(dom,type) do { } while (0)
+static inline void set_domain(unsigned val) { }
+static inline void modify_domain(unsigned dom, unsigned type) { }
#endif
/*
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9
-#define TIF_SYSCALL_RESTARTSYS 10
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS)
/* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
- _TIF_SYSCALL_RESTARTSYS)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
/*
* Change these and you break ASM code in entry-common.S
TEST_BF_R ("mov pc, r",0,2f,"")
TEST_BF_RR("mov pc, r",0,2f,", asl r",1,0,"")
TEST_BB( "sub pc, pc, #1b-2b+8")
-#if __LINUX_ARM_ARCH__ >= 6
- TEST_BB( "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before ARMv6 */
+#if __LINUX_ARM_ARCH__ == 6 && !defined(CONFIG_CPU_V7)
+ TEST_BB( "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before and after ARMv6 */
#endif
TEST_BB_R( "sub pc, pc, r",14, 1f-2f+8,"")
TEST_BB_R( "rsb pc, r",14,1f-2f+8,", pc")
event_requires_mode_exclusion(&event->attr)) {
pr_debug("ARM performance counters do not support "
"mode exclusion\n");
- return -EPERM;
+ return -EOPNOTSUPP;
}
/*
#include <linux/regset.h>
#include <linux/audit.h>
#include <linux/tracehook.h>
-#include <linux/unistd.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
- if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
- scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return scno;
*/
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
+#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)
/*
* With EABI, the syscall number has to be loaded into r7.
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
};
+/*
+ * Either we support OABI only, or we have EABI with the OABI
+ * compat layer enabled. In the later case we don't know if
+ * user space is EABI or not, and if not we must not clobber r7.
+ * Always using the OABI syscall solves that issue and works for
+ * all those cases.
+ */
+const unsigned long syscall_restart_code[2] = {
+ SWI_SYS_RESTART, /* swi __NR_restart_syscall */
+ 0xe49df004, /* ldr pc, [sp], #4 */
+};
+
/*
* atomically swap in the new signal mask, and wait for a signal.
*/
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
- case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = regs->ARM_ORIG_r0;
regs->ARM_pc = restart_addr;
break;
+ case -ERESTART_RESTARTBLOCK:
+ regs->ARM_r0 = -EINTR;
+ break;
}
}
* debugger has chosen to restart at a different PC.
*/
if (regs->ARM_pc == restart_addr) {
- if (retval == -ERESTARTNOHAND ||
- retval == -ERESTART_RESTARTBLOCK
+ if (retval == -ERESTARTNOHAND
|| (retval == -ERESTARTSYS
&& !(ka.sa.sa_flags & SA_RESTART))) {
regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr;
}
- clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
}
handle_signal(signr, &ka, &info, regs);
* ignore the restart.
*/
if (retval == -ERESTART_RESTARTBLOCK
- && regs->ARM_pc == restart_addr)
- set_thread_flag(TIF_SYSCALL_RESTARTSYS);
+ && regs->ARM_pc == continue_addr) {
+ if (thumb_mode(regs)) {
+ regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
+ regs->ARM_pc -= 2;
+ } else {
+#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
+ regs->ARM_r7 = __NR_restart_syscall;
+ regs->ARM_pc -= 4;
+#else
+ u32 __user *usp;
+
+ regs->ARM_sp -= 4;
+ usp = (u32 __user *)regs->ARM_sp;
+
+ if (put_user(regs->ARM_pc, usp) == 0) {
+ regs->ARM_pc = KERN_RESTART_CODE;
+ } else {
+ regs->ARM_sp += 4;
+ force_sigsegv(0, current);
+ }
+#endif
+ }
+ }
}
restore_saved_sigmask();
* published by the Free Software Foundation.
*/
#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500)
+#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
extern const unsigned long sigreturn_codes[7];
+extern const unsigned long syscall_restart_code[2];
*/
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
sigreturn_codes, sizeof(sigreturn_codes));
+ memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
+ syscall_restart_code, sizeof(syscall_restart_code));
flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
#endif
+#ifdef CONFIG_SMP
PERCPU_SECTION(L1_CACHE_BYTES)
+#endif
#ifdef CONFIG_XIP_KERNEL
__data_loc = ALIGN(4); /* location in binary */
#define POWER_MANAGEMENT (BRIDGE_VIRT_BASE | 0x011c)
#define TIMER_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0300)
+#define TIMER_PHYS_BASE (BRIDGE_PHYS_BASE | 0x0300)
#endif
/* North-South Bridge */
#define BRIDGE_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0x20000)
+#define BRIDGE_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE | 0x20000)
/* Cryptographic Engine */
#define DOVE_CRYPT_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE | 0x30000)
struct exynos_pm_domain *pd)
{
if (pdev->dev.bus) {
- if (pm_genpd_add_device(&pd->pd, &pdev->dev))
+ if (!pm_genpd_add_device(&pd->pd, &pdev->dev))
+ pm_genpd_dev_need_restore(&pdev->dev, true);
+ else
pr_info("%s: error in adding %s device to %s power"
"domain\n", __func__, dev_name(&pdev->dev),
pd->name);
if (of_have_populated_dt())
return exynos_pm_dt_parse_domains();
- for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++)
- pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL,
- exynos4_pm_domains[idx]->is_off);
+ for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) {
+ struct exynos_pm_domain *pd = exynos4_pm_domains[idx];
+ int on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN;
+
+ pm_genpd_init(&pd->pd, NULL, !on);
+ }
#ifdef CONFIG_S5P_DEV_FIMD0
exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0);
pr_err("i.MX35 clk %d: register failed with %ld\n",
i, PTR_ERR(clk[i]));
-
clk_register_clkdev(clk[pata_gate], NULL, "pata_imx");
clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0");
clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1");
clk_prepare_enable(clk[iim_gate]);
clk_prepare_enable(clk[emi_gate]);
+ /*
+ * SCC is needed to boot via mmc after a watchdog reset. The clock code
+ * before conversion to common clk also enabled UART1 (which isn't
+ * handled here and not needed for mmc) and IIM (which is enabled
+ * unconditionally above).
+ */
+ clk_prepare_enable(clk[scc_gate]);
+
imx_print_silicon_rev("i.MX35", mx35_revision());
#ifdef CONFIG_MXC_USE_EPIT
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-#include <asm/system.h>
+#include <asm/system_info.h>
#include <mach/common.h>
#include <mach/iomux-mx27.h>
+++ /dev/null
-#ifndef __ASM_MACH_GPIO_PXA_H
-#define __ASM_MACH_GPIO_PXA_H
-
-#include <mach/addr-map.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-
-#define GPIO_REGS_VIRT (APB_VIRT_BASE + 0x19000)
-
-#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
-#define GPIO_REG(x) (*(volatile u32 *)(GPIO_REGS_VIRT + (x)))
-
-#define gpio_to_bank(gpio) ((gpio) >> 5)
-
-/* NOTE: these macros are defined here to make optimization of
- * gpio_{get,set}_value() to work when 'gpio' is a constant.
- * Usage of these macros otherwise is no longer recommended,
- * use generic GPIO API whenever possible.
- */
-#define GPIO_bit(gpio) (1 << ((gpio) & 0x1f))
-
-#define GPLR(x) GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x00)
-#define GPDR(x) GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x0c)
-#define GPSR(x) GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x18)
-#define GPCR(x) GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x24)
-
-#include <plat/gpio-pxa.h>
-
-#endif /* __ASM_MACH_GPIO_PXA_H */
#define IRQ_MASK_HIGH_OFF 0x0014
#define TIMER_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0300)
+#define TIMER_PHYS_BASE (BRIDGE_PHYS_BASE | 0x0300)
#endif
#define MV78XX0_CORE0_REGS_PHYS_BASE 0xf1020000
#define MV78XX0_CORE1_REGS_PHYS_BASE 0xf1024000
#define MV78XX0_CORE_REGS_VIRT_BASE 0xfe400000
+#define MV78XX0_CORE_REGS_PHYS_BASE 0xfe400000
#define MV78XX0_CORE_REGS_SIZE SZ_16K
#define MV78XX0_PCIE_IO_PHYS_BASE(i) (0xf0800000 + ((i) << 20))
* Core-specific peripheral registers.
*/
#define BRIDGE_VIRT_BASE (MV78XX0_CORE_REGS_VIRT_BASE)
+#define BRIDGE_PHYS_BASE (MV78XX0_CORE_REGS_PHYS_BASE)
/*
* Register Map
return 0;
}
+static void __init apx4devkit_fec_phy_clk_enable(void)
+{
+ struct clk *clk;
+
+ /* Enable fec phy clock */
+ clk = clk_get_sys("enet_out", NULL);
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+}
+
static void __init apx4devkit_init(void)
{
mx28_soc_init();
phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
apx4devkit_phy_fixup);
+ apx4devkit_fec_phy_clk_enable();
mx28_add_fec(0, &mx28_fec_pdata);
mx28_add_mxs_mmc(0, &apx4devkit_mmc_pdata);
regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap_hsmmc_init(mmc);
overo_i2c_init();
+ omap_hsmmc_init(mmc);
omap_display_init(&overo_dss_data);
omap_serial_init();
omap_sdrc_init(mt46h32m32lf6_sdrc_params,
*
* CLKDM_NO_AUTODEPS: Prevent "autodeps" from being added/removed from this
* clockdomain. (Currently, this applies to OMAP3 clockdomains only.)
+ * CLKDM_ACTIVE_WITH_MPU: The PRCM guarantees that this clockdomain is
+ * active whenever the MPU is active. True for interconnects and
+ * the WKUP clockdomains.
*/
#define CLKDM_CAN_FORCE_SLEEP (1 << 0)
#define CLKDM_CAN_FORCE_WAKEUP (1 << 1)
#define CLKDM_CAN_ENABLE_AUTO (1 << 2)
#define CLKDM_CAN_DISABLE_AUTO (1 << 3)
#define CLKDM_NO_AUTODEPS (1 << 4)
+#define CLKDM_ACTIVE_WITH_MPU (1 << 5)
#define CLKDM_CAN_HWSUP (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
#define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
.name = "wkup_clkdm",
.pwrdm = { .name = "wkup_pwrdm" },
.dep_bit = OMAP_EN_WKUP_SHIFT,
+ .flags = CLKDM_ACTIVE_WITH_MPU,
};
.cm_inst = OMAP4430_PRM_WKUP_CM_INST,
.clkdm_offs = OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS,
.dep_bit = OMAP4430_L4WKUP_STATDEP_SHIFT,
- .flags = CLKDM_CAN_HWSUP,
+ .flags = CLKDM_CAN_HWSUP | CLKDM_ACTIVE_WITH_MPU,
};
static struct clockdomain emu_sys_44xx_clkdm = {
* _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
- * If module is marked as SWSUP_SIDLE, force the module out of slave
- * idle; otherwise, configure it for smart-idle. If module is marked
- * as SWSUP_MSUSPEND, force the module out of master standby;
- * otherwise, configure it for smart-standby. No return value.
+ * Ensure that the OCP_SYSCONFIG register for the IP block represented
+ * by @oh is set to indicate to the PRCM that the IP block is active.
+ * Usually this means placing the module into smart-idle mode and
+ * smart-standby, but if there is a bug in the automatic idle handling
+ * for the IP block, it may need to be placed into the force-idle or
+ * no-idle variants of these modes. No return value.
*/
static void _enable_sysc(struct omap_hwmod *oh)
{
u8 idlemode, sf;
u32 v;
+ bool clkdm_act;
if (!oh->class->sysc)
return;
sf = oh->class->sysc->sysc_flags;
if (sf & SYSC_HAS_SIDLEMODE) {
- idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
- HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
+ clkdm_act = ((oh->clkdm &&
+ oh->clkdm->flags & CLKDM_ACTIVE_WITH_MPU) ||
+ (oh->_clk && oh->_clk->clkdm &&
+ oh->_clk->clkdm->flags & CLKDM_ACTIVE_WITH_MPU));
+ if (clkdm_act && !(oh->class->sysc->idlemodes &
+ (SIDLE_SMART | SIDLE_SMART_WKUP)))
+ idlemode = HWMOD_IDLEMODE_FORCE;
+ else
+ idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
+ HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
_set_slave_idlemode(oh, idlemode, &v);
}
sf = oh->class->sysc->sysc_flags;
if (sf & SYSC_HAS_SIDLEMODE) {
- idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
- HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART;
+ /* XXX What about HWMOD_IDLEMODE_SMART_WKUP? */
+ if (oh->flags & HWMOD_SWSUP_SIDLE ||
+ !(oh->class->sysc->idlemodes &
+ (SIDLE_SMART | SIDLE_SMART_WKUP)))
+ idlemode = HWMOD_IDLEMODE_FORCE;
+ else
+ idlemode = HWMOD_IDLEMODE_SMART;
_set_slave_idlemode(oh, idlemode, &v);
}
static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
- { .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
+ { .role = "prcm_fck", .clk = "mcbsp1_sync_mux_ck" },
};
static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
- { .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
+ { .role = "prcm_fck", .clk = "mcbsp2_sync_mux_ck" },
};
static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
- { .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
+ { .role = "prcm_fck", .clk = "mcbsp3_sync_mux_ck" },
};
static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
- { .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
+ { .role = "prcm_fck", .clk = "mcbsp4_sync_mux_ck" },
};
static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
};
/* usb_host_fs -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_usb_host_fs__l3_main_2 = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_usb_host_fs__l3_main_2 = {
.master = &omap44xx_usb_host_fs_hwmod,
.slave = &omap44xx_l3_main_2_hwmod,
.clk = "l3_div_ck",
};
/* aess -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_aess__l4_abe = {
.master = &omap44xx_aess_hwmod,
.slave = &omap44xx_l4_abe_hwmod,
.clk = "ocp_abe_iclk",
};
/* l4_abe -> aess */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_abe__aess = {
.master = &omap44xx_l4_abe_hwmod,
.slave = &omap44xx_aess_hwmod,
.clk = "ocp_abe_iclk",
};
/* l4_abe -> aess (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess_dma = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_abe__aess_dma = {
.master = &omap44xx_l4_abe_hwmod,
.slave = &omap44xx_aess_hwmod,
.clk = "ocp_abe_iclk",
};
/* l4_cfg -> usb_host_fs */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_fs = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_cfg__usb_host_fs = {
.master = &omap44xx_l4_cfg_hwmod,
.slave = &omap44xx_usb_host_fs_hwmod,
.clk = "l4_div_ck",
&omap44xx_iva__l3_main_2,
&omap44xx_l3_main_1__l3_main_2,
&omap44xx_l4_cfg__l3_main_2,
- &omap44xx_usb_host_fs__l3_main_2,
+ /* &omap44xx_usb_host_fs__l3_main_2, */
&omap44xx_usb_host_hs__l3_main_2,
&omap44xx_usb_otg_hs__l3_main_2,
&omap44xx_l3_main_1__l3_main_3,
&omap44xx_l3_main_2__l3_main_3,
&omap44xx_l4_cfg__l3_main_3,
- &omap44xx_aess__l4_abe,
+ /* &omap44xx_aess__l4_abe, */
&omap44xx_dsp__l4_abe,
&omap44xx_l3_main_1__l4_abe,
&omap44xx_mpu__l4_abe,
&omap44xx_l4_cfg__l4_wkup,
&omap44xx_mpu__mpu_private,
&omap44xx_l4_cfg__ocp_wp_noc,
- &omap44xx_l4_abe__aess,
- &omap44xx_l4_abe__aess_dma,
+ /* &omap44xx_l4_abe__aess, */
+ /* &omap44xx_l4_abe__aess_dma, */
&omap44xx_l3_main_2__c2c,
&omap44xx_l4_wkup__counter_32k,
&omap44xx_l4_cfg__ctrl_module_core,
&omap44xx_l4_per__uart2,
&omap44xx_l4_per__uart3,
&omap44xx_l4_per__uart4,
- &omap44xx_l4_cfg__usb_host_fs,
+ /* &omap44xx_l4_cfg__usb_host_fs, */
&omap44xx_l4_cfg__usb_host_hs,
&omap44xx_l4_cfg__usb_otg_hs,
&omap44xx_l4_cfg__usb_tll_hs,
#include "twl-common.h"
#include "pm.h"
#include "voltage.h"
+#include "mux.h"
static struct i2c_board_info __initdata pmic_i2c_board_info = {
.addr = 0x48,
struct twl6040_platform_data *twl6040_data, int twl6040_irq)
{
/* PMIC part*/
+ omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
strncpy(omap4_i2c1_board_info[0].type, pmic_type,
sizeof(omap4_i2c1_board_info[0].type));
omap4_i2c1_board_info[0].irq = OMAP44XX_IRQ_SYS_1N;
GPIO19_SSP2_SCLK,
GPIO86_SSP2_RXD,
GPIO87_SSP2_TXD,
- GPIO88_GPIO,
+ GPIO88_GPIO | MFP_LPM_DRIVE_HIGH, /* TSC2046_CS */
+
+ /* BQ24022 Regulator */
+ GPIO72_GPIO | MFP_LPM_KEEP_OUTPUT, /* BQ24022_nCHARGE_EN */
+ GPIO96_GPIO | MFP_LPM_KEEP_OUTPUT, /* BQ24022_ISET2 */
/* HX4700 specific input GPIOs */
GPIO12_GPIO | WAKEUP_ON_EDGE_RISE, /* ASIC3_IRQ */
GPIO14_GPIO, /* nWLAN_IRQ */
/* HX4700 specific output GPIOs */
+ GPIO61_GPIO | MFP_LPM_DRIVE_HIGH, /* W3220_nRESET */
+ GPIO71_GPIO | MFP_LPM_DRIVE_HIGH, /* ASIC3_nRESET */
+ GPIO81_GPIO | MFP_LPM_DRIVE_HIGH, /* CPU_GP_nRESET */
+ GPIO116_GPIO | MFP_LPM_DRIVE_HIGH, /* CPU_HW_nRESET */
GPIO102_GPIO | MFP_LPM_DRIVE_LOW, /* SYNAPTICS_POWER_ON */
GPIO10_GPIO, /* GSM_IRQ */
{ GPIO110_HX4700_LCD_LVDD_3V3_ON, GPIOF_OUT_INIT_HIGH, "LCD_LVDD" },
{ GPIO111_HX4700_LCD_AVDD_3V3_ON, GPIOF_OUT_INIT_HIGH, "LCD_AVDD" },
{ GPIO32_HX4700_RS232_ON, GPIOF_OUT_INIT_HIGH, "RS232_ON" },
+ { GPIO61_HX4700_W3220_nRESET, GPIOF_OUT_INIT_HIGH, "W3220_nRESET" },
{ GPIO71_HX4700_ASIC3_nRESET, GPIOF_OUT_INIT_HIGH, "ASIC3_nRESET" },
+ { GPIO81_HX4700_CPU_GP_nRESET, GPIOF_OUT_INIT_HIGH, "CPU_GP_nRESET" },
{ GPIO82_HX4700_EUART_RESET, GPIOF_OUT_INIT_HIGH, "EUART_RESET" },
+ { GPIO116_HX4700_CPU_HW_nRESET, GPIOF_OUT_INIT_HIGH, "CPU_HW_nRESET" },
};
static void __init hx4700_init(void)
{
int ret;
+ PCFR = PCFR_GPR_EN | PCFR_OPDE;
+
pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
gpio_set_wake(GPIO12_HX4700_ASIC3_IRQ, 1);
ret = gpio_request_array(ARRAY_AND_SIZE(global_gpios));
static struct clk s3c2440_clk_ac97 = {
.name = "ac97",
.enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2440_CLKCON_CAMERA,
+ .ctrlbit = S3C2440_CLKCON_AC97,
};
static unsigned long s3c2440_fclk_n_getrate(struct clk *clk)
#include <mach/common.h>
#include <mach/emev2.h>
+#ifdef CONFIG_ARCH_SH73A0
#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
of_machine_is_compatible("renesas,sh73a0"))
+#else
+#define is_sh73a0() (0)
+#endif
+
#define is_r8a7779() machine_is_marzen()
#ifdef CONFIG_ARCH_EMEV2
&ab8500_device,
};
-static struct platform_device *snowball_of_platform_devs[] __initdata = {
- &snowball_led_dev,
- &snowball_key_dev,
-};
-
static void __init mop500_init_machine(void)
{
struct device *parent = NULL;
#ifdef CONFIG_MACH_UX500_DT
+static struct platform_device *snowball_of_platform_devs[] __initdata = {
+ &snowball_led_dev,
+ &snowball_key_dev,
+};
+
struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
/* Requires DMA and call-back bindings. */
OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e000, "gpio.6", NULL),
OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e080, "gpio.7", NULL),
OF_DEV_AUXDATA("st,nomadik-gpio", 0xa03fe000, "gpio.8", NULL),
+ /* Requires device name bindings. */
+ OF_DEV_AUXDATA("stericsson,nmk_pinctrl", 0, "pinctrl-db8500", NULL),
{},
};
/* TODO: Once MTU has been DT:ed place code above into else. */
if (of_have_populated_dt()) {
+#ifdef CONFIG_OF
np = of_find_matching_node(NULL, prcmu_timer_of_match);
if (!np)
+#endif
goto dt_fail;
tmp_base = of_iomap(np, 0);
static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;
- int devslot = PCI_SLOT(dev->devfn);
/* slot, pin, irq
* 24 1 27
#ifdef CONFIG_ZONE_DMA
extern phys_addr_t arm_dma_limit;
#else
-#define arm_dma_limit ((u32)~0)
+#define arm_dma_limit ((phys_addr_t)~0)
#endif
extern phys_addr_t arm_lowmem_limit;
}
}
+#ifndef CONFIG_ARM_LPAE
+
+/*
+ * The Linux PMD is made of two consecutive section entries covering 2MB
+ * (see definition in include/asm/pgtable-2level.h). However a call to
+ * create_mapping() may optimize static mappings by using individual
+ * 1MB section mappings. This leaves the actual PMD potentially half
+ * initialized if the top or bottom section entry isn't used, leaving it
+ * open to problems if a subsequent ioremap() or vmalloc() tries to use
+ * the virtual space left free by that unused section entry.
+ *
+ * Let's avoid the issue by inserting dummy vm entries covering the unused
+ * PMD halves once the static mappings are in place.
+ */
+
+static void __init pmd_empty_section_gap(unsigned long addr)
+{
+ struct vm_struct *vm;
+
+ vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+ vm->addr = (void *)addr;
+ vm->size = SECTION_SIZE;
+ vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+ vm->caller = pmd_empty_section_gap;
+ vm_area_add_early(vm);
+}
+
+static void __init fill_pmd_gaps(void)
+{
+ struct vm_struct *vm;
+ unsigned long addr, next = 0;
+ pmd_t *pmd;
+
+ /* we're still single threaded hence no lock needed here */
+ for (vm = vmlist; vm; vm = vm->next) {
+ if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+ continue;
+ addr = (unsigned long)vm->addr;
+ if (addr < next)
+ continue;
+
+ /*
+ * Check if this vm starts on an odd section boundary.
+ * If so and the first section entry for this PMD is free
+ * then we block the corresponding virtual address.
+ */
+ if ((addr & ~PMD_MASK) == SECTION_SIZE) {
+ pmd = pmd_off_k(addr);
+ if (pmd_none(*pmd))
+ pmd_empty_section_gap(addr & PMD_MASK);
+ }
+
+ /*
+ * Then check if this vm ends on an odd section boundary.
+ * If so and the second section entry for this PMD is empty
+ * then we block the corresponding virtual address.
+ */
+ addr += vm->size;
+ if ((addr & ~PMD_MASK) == SECTION_SIZE) {
+ pmd = pmd_off_k(addr) + 1;
+ if (pmd_none(*pmd))
+ pmd_empty_section_gap(addr);
+ }
+
+ /* no need to look at any vm entry until we hit the next PMD */
+ next = (addr + PMD_SIZE - 1) & PMD_MASK;
+ }
+}
+
+#else
+#define fill_pmd_gaps() do { } while (0)
+#endif
+
static void * __initdata vmalloc_min =
(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
*/
if (mdesc->map_io)
mdesc->map_io();
+ fill_pmd_gaps();
/*
* Finally flush the caches and tlb to ensure that we're in a
return -EINVAL;
}
- if (client->is_ts && adc->ts_pend)
- return -EAGAIN;
-
spin_lock_irqsave(&adc->lock, flags);
+ if (client->is_ts && adc->ts_pend) {
+ spin_unlock_irqrestore(&adc->lock, flags);
+ return -EAGAIN;
+ }
+
client->channel = channel;
client->nr_samples = nr_samples;
#ifdef CONFIG_CPU_S3C2440
static struct resource s3c_camif_resource[] = {
[0] = DEFINE_RES_MEM(S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF),
- [1] = DEFINE_RES_IRQ(IRQ_CAM),
+ [1] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_C),
+ [2] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_P),
};
struct platform_device s3c_device_camif = {
struct clk clk_xusbxti = {
.name = "xusbxti",
.id = -1,
+ .rate = 24000000,
};
struct clk s5p_clk_27m = {
#define VMALLOC_END 0xffffffff
#define arch_enter_lazy_cpu_mode() do {} while (0)
+
+#include <asm-generic/pgtable.h>
+
#endif /* _H8300_PGTABLE_H */
break; \
default: \
__gu_err = __get_user_bad(); \
- __gu_val = 0; \
break; \
} \
(x) = __gu_val; \
return 0;
}
+#define __clear_user clear_user
+
#endif /* _H8300_UACCESS_H */
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-statis void do_signal(struct pt_regs *regs)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
#include <linux/profile.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#include <asm/timer.h>
#define TICK_SIZE (tick_nsec / 1000)
/* setup reset gpio used by pci */
reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
- if (reset_gpio > 0)
+ if (gpio_is_valid(reset_gpio))
devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
/* enable auto-switching between PCI and EBU */
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
/* toggle reset pin */
- if (reset_gpio > 0) {
+ if (gpio_is_valid(reset_gpio)) {
__gpio_set_value(reset_gpio, 0);
wmb();
mdelay(1);
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
-
#ifdef __KERNEL__
#define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
}
#ifndef CONFIG_KGDB
-void arch_release_thread_info(struct thread_info *ti)
+void arch_release_thread_info(struct thread_info *ti);
#endif
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
#ifndef _ASM_TIMEX_H
#define _ASM_TIMEX_H
-#include <asm/hardirq.h>
#include <unit/timex.h>
#define TICK_SIZE (tick_nsec / 1000)
extern int init_clockevents(void);
extern int init_clocksource(void);
-static inline void setup_jiffies_interrupt(int irq,
- struct irqaction *action)
-{
- u16 tmp;
- setup_irq(irq, action);
- set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
- GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
- tmp = GxICR(irq);
-}
-
#endif /* __KERNEL__ */
#endif /* _ASM_TIMEX_H */
{
}
+static inline void setup_jiffies_interrupt(int irq,
+ struct irqaction *action)
+{
+ u16 tmp;
+ setup_irq(irq, action);
+ set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
+ GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
+ tmp = GxICR(irq);
+}
+
int __init init_clockevents(void)
{
struct clock_event_device *cd;
* 2 of the Licence, or (at your option) any later version.
*/
+#include <linux/irqreturn.h>
+
struct clocksource;
struct clock_event_device;
case SC1TXIRQ:
#ifdef CONFIG_MN10300_TTYSM1_TIMER12
case TM12IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER9
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER9)
case TM9IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER3
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
case TM3IRQ:
#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
#endif /* CONFIG_MN10300_TTYSM1 */
#include <linux/kdebug.h>
#include <linux/bug.h>
#include <linux/irq.h>
+#include <linux/export.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/gfp.h>
+#include <linux/export.h>
#include <asm/io.h>
static unsigned long pci_sram_allocated = 0xbc000000;
#ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
#include <asm/timer-regs.h>
#include <unit/clock.h>
#include <asm/param.h>
#include <linux/platform_device.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/timex.h>
#include <asm/processor.h>
#include <asm/intctl-regs.h>
#ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
#include <asm/timer-regs.h>
#include <unit/clock.h>
#include <asm/param.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/processor.h>
#include <asm/intctl-regs.h>
#ifndef _ASM_UNIT_TIMEX_H
#define _ASM_UNIT_TIMEX_H
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
#include <asm/timer-regs.h>
#include <unit/clock.h>
#include <asm/param.h>
}
#ifdef CONFIG_PPC_BOOK3E
-#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory");
-#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory");
+#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory")
+#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory")
#else
#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1)
return !regs->softe;
}
+extern bool prep_irq_for_idle(void);
+
#else /* CONFIG_PPC64 */
#define SET_MSR_EE(x) mtmsr(x)
*/
if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
__hard_irq_disable();
-#ifdef CONFIG_TRACE_IRQFLAG
+#ifdef CONFIG_TRACE_IRQFLAGS
else {
/*
* We should already be hard disabled here. We had bugs
__hard_irq_enable();
}
+/*
+ * This is a helper to use when about to go into idle low-power
+ * when the latter has the side effect of re-enabling interrupts
+ * (such as calling H_CEDE under pHyp).
+ *
+ * You call this function with interrupts soft-disabled (this is
+ * already the case when ppc_md.power_save is called). The function
+ * will return whether to enter power save or just return.
+ *
+ * In the former case, it will have notified lockdep of interrupts
+ * being re-enabled and generally sanitized the lazy irq state,
+ * and in the latter case it will leave with interrupts hard
+ * disabled and marked as such, so the local_irq_enable() call
+ * in cpu_idle() will properly re-enable everything.
+ */
+bool prep_irq_for_idle(void)
+{
+ /*
+ * First we need to hard disable to ensure no interrupt
+ * occurs before we effectively enter the low power state
+ */
+ hard_irq_disable();
+
+ /*
+ * If anything happened while we were soft-disabled,
+ * we return now and do not enter the low power state.
+ */
+ if (lazy_irq_pending())
+ return false;
+
+ /* Tell lockdep we are about to re-enable */
+ trace_hardirqs_on();
+
+ /*
+ * Mark interrupts as soft-enabled and clear the
+ * PACA_IRQ_HARD_DIS from the pending mask since we
+ * are about to hard enable as well as a side effect
+ * of entering the low power state.
+ */
+ local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
+ local_paca->soft_enabled = 1;
+
+ /* Tell the caller to enter the low power state */
+ return true;
+}
+
#endif /* CONFIG_PPC64 */
int arch_show_interrupts(struct seq_file *p, int prec)
lwz r3,VCORE_NAPPING_THREADS(r5)
lwz r4,VCPU_PTID(r9)
li r0,1
- sldi r0,r0,r4
+ sld r0,r0,r4
andc. r3,r3,r0 /* no sense IPI'ing ourselves */
beq 43f
mulli r4,r4,PACA_SIZE /* get paca for thread 0 */
case H_PUT_TCE:
return kvmppc_h_pr_put_tce(vcpu);
case H_CEDE:
+ vcpu->arch.shared->msr |= MSR_EE;
kvm_vcpu_block(vcpu);
clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
vcpu->stat.halt_wakeup++;
unsigned int n, rc, ranges, is_kexec_kdump = 0;
unsigned long lmb_size, base, size, sz;
int nid;
- struct assoc_arrays aa;
+ struct assoc_arrays aa = { .arrays = NULL };
n = of_get_drconf_memory(memory, &dm);
if (!n)
{
unsigned long ctrl, thread_switch_control;
- /*
- * We need to hard disable interrupts, the local_irq_enable() done by
- * our caller upon return will hard re-enable.
- */
- hard_irq_disable();
+ /* Ensure our interrupt state is properly tracked */
+ if (!prep_irq_for_idle())
+ return;
ctrl = mfspr(SPRN_CTRLF);
*/
ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
mtspr(SPRN_CTRLT, ctrl);
+
+ /* Re-enable interrupts in MSR */
+ __hard_irq_enable();
}
static int cbe_system_reset_exception(struct pt_regs *regs)
static void check_and_cede_processor(void)
{
/*
- * Interrupts are soft-disabled at this point,
- * but not hard disabled. So an interrupt might have
- * occurred before entering NAP, and would be potentially
- * lost (edge events, decrementer events, etc...) unless
- * we first hard disable then check.
+ * Ensure our interrupt state is properly tracked,
+ * also checks if no interrupt has occurred while we
+ * were soft-disabled
*/
- hard_irq_disable();
- if (!lazy_irq_pending())
+ if (prep_irq_for_idle()) {
cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
+#endif
+ }
}
static int dedicated_cede_loop(struct cpuidle_device *dev,
/* print cpus waiting or in xmon */
printf("cpus stopped:");
count = 0;
- for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+ for_each_possible_cpu(cpu) {
if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
if (count == 0)
printf(" %x", cpu);
return -1;
}
-#define outb(x, y) BUG()
-#define outw(x, y) BUG()
-#define outl(x, y) BUG()
+static inline void outb(unsigned char x, unsigned long port)
+{
+ BUG();
+}
+
+static inline void outw(unsigned short x, unsigned long port)
+{
+ BUG();
+}
+
+static inline void outl(unsigned int x, unsigned long port)
+{
+ BUG();
+}
#define inb_p(addr) inb(addr)
#define inw_p(addr) inw(addr)
#include <linux/serial_core.h>
#include <linux/io.h>
#include <cpu/serial.h>
-#include <asm/gpio.h>
+#include <cpu/gpio.h>
static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)
{
#include <linux/kernel.h>
#include <linux/string.h>
+#include <asm/byteorder.h>
#include <asm/backtrace.h>
#include <asm/tile-desc.h>
#include <arch/abi.h>
bytes_to_prefetch / sizeof(tile_bundle_bits);
}
- /* Decode the next bundle. */
- bundle.bits = prefetched_bundles[next_bundle++];
+ /*
+ * Decode the next bundle.
+ * TILE always stores instruction bundles in little-endian
+ * mode, even when the chip is running in big-endian mode.
+ */
+ bundle.bits = le64_to_cpu(prefetched_bundles[next_bundle++]);
bundle.num_insns =
parse_insn_tile(bundle.bits, pc, bundle.insns);
num_info_ops = bt_get_info_ops(&bundle, info_operands);
struct task_struct *from = current, *to = arg;
to->thread.saved_task = from;
- rcu_switch_from(from);
switch_to(from, to, from);
}
return nr;
}
+#ifdef CONFIG_SECCOMP
+static int vsyscall_seccomp(struct task_struct *tsk, int syscall_nr)
+{
+ if (!seccomp_mode(&tsk->seccomp))
+ return 0;
+ task_pt_regs(tsk)->orig_ax = syscall_nr;
+ task_pt_regs(tsk)->ax = syscall_nr;
+ return __secure_computing(syscall_nr);
+}
+#else
+#define vsyscall_seccomp(_tsk, _nr) 0
+#endif
+
static bool write_ok_or_segv(unsigned long ptr, size_t size)
{
/*
int vsyscall_nr;
int prev_sig_on_uaccess_error;
long ret;
+ int skip;
/*
* No point in checking CS -- the only way to get here is a user mode
}
tsk = current;
- if (seccomp_mode(&tsk->seccomp))
- do_exit(SIGKILL);
-
/*
* With a real vsyscall, page faults cause SIGSEGV. We want to
* preserve that behavior to make writing exploits harder.
* address 0".
*/
ret = -EFAULT;
+ skip = 0;
switch (vsyscall_nr) {
case 0:
+ skip = vsyscall_seccomp(tsk, __NR_gettimeofday);
+ if (skip)
+ break;
+
if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) ||
!write_ok_or_segv(regs->si, sizeof(struct timezone)))
break;
break;
case 1:
+ skip = vsyscall_seccomp(tsk, __NR_time);
+ if (skip)
+ break;
+
if (!write_ok_or_segv(regs->di, sizeof(time_t)))
break;
break;
case 2:
+ skip = vsyscall_seccomp(tsk, __NR_getcpu);
+ if (skip)
+ break;
+
if (!write_ok_or_segv(regs->di, sizeof(unsigned)) ||
!write_ok_or_segv(regs->si, sizeof(unsigned)))
break;
current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error;
+ if (skip) {
+ if ((long)regs->ax <= 0L) /* seccomp errno emulation */
+ goto do_ret;
+ goto done; /* seccomp trace/trap */
+ }
+
if (ret == -EFAULT) {
/* Bad news -- userspace fed a bad pointer to a vsyscall. */
warn_bad_vsyscall(KERN_INFO, regs,
regs->ax = ret;
+do_ret:
/* Emulate a ret instruction. */
regs->ip = caller;
regs->sp += 8;
-
+done:
return true;
sigsegv:
{
struct kvm_mmu_page *page;
+ if (list_empty(&kvm->arch.active_mmu_pages))
+ return;
+
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
/* Don't leak any random bits. */
- memset(elfregs, 0, sizeof (elfregs));
+ memset(elfregs, 0, sizeof(*elfregs));
/* Note: PS.EXCM is not set while user task is running; its
* being set in regs->ps is for exception handling convenience.
blkg->pd[i] = pd;
pd->blkg = blkg;
- }
-
- /* invoke per-policy init */
- for (i = 0; i < BLKCG_MAX_POLS; i++) {
- struct blkcg_policy *pol = blkcg_policy[i];
+ /* invoke per-policy init */
if (blkcg_policy_enabled(blkg->q, pol))
pol->pd_init_fn(blkg);
}
static void blkg_destroy(struct blkcg_gq *blkg)
{
- struct request_queue *q = blkg->q;
struct blkcg *blkcg = blkg->blkcg;
- lockdep_assert_held(q->queue_lock);
+ lockdep_assert_held(blkg->q->queue_lock);
lockdep_assert_held(&blkcg->lock);
/* Something wrong if we are trying to remove same group twice */
*/
void blk_drain_queue(struct request_queue *q, bool drain_all)
{
+ int i;
+
while (true) {
bool drain = false;
- int i;
spin_lock_irq(q->queue_lock);
break;
msleep(10);
}
+
+ /*
+ * With queue marked dead, any woken up waiter will fail the
+ * allocation path, so the wakeup chaining is lost and we're
+ * left with hung waiters. We need to wake up those waiters.
+ */
+ if (q->request_fn) {
+ spin_lock_irq(q->queue_lock);
+ for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
+ wake_up_all(&q->rq.wait[i]);
+ spin_unlock_irq(q->queue_lock);
+ }
}
/**
/* mark @q DEAD, no new request or merges will be allowed afterwards */
mutex_lock(&q->sysfs_lock);
queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
-
spin_lock_irq(lock);
/*
queue_flag_set(QUEUE_FLAG_NOMERGES, q);
queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
queue_flag_set(QUEUE_FLAG_DEAD, q);
-
- if (q->queue_lock != &q->__queue_lock)
- q->queue_lock = &q->__queue_lock;
-
spin_unlock_irq(lock);
mutex_unlock(&q->sysfs_lock);
del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
blk_sync_queue(q);
+ spin_lock_irq(lock);
+ if (q->queue_lock != &q->__queue_lock)
+ q->queue_lock = &q->__queue_lock;
+ spin_unlock_irq(lock);
+
/* @q is and will stay empty, shutdown and put */
blk_put_queue(q);
}
mod_timer(&q->timeout, expiry);
}
-/**
- * blk_abort_queue -- Abort all request on given queue
- * @queue: pointer to queue
- *
- */
-void blk_abort_queue(struct request_queue *q)
-{
- unsigned long flags;
- struct request *rq, *tmp;
- LIST_HEAD(list);
-
- /*
- * Not a request based block device, nothing to abort
- */
- if (!q->request_fn)
- return;
-
- spin_lock_irqsave(q->queue_lock, flags);
-
- elv_abort_queue(q);
-
- /*
- * Splice entries to local list, to avoid deadlocking if entries
- * get readded to the timeout list by error handling
- */
- list_splice_init(&q->timeout_list, &list);
-
- list_for_each_entry_safe(rq, tmp, &list, timeout_list)
- blk_abort_request(rq);
-
- /*
- * Occasionally, blk_abort_request() will return without
- * deleting the element from the list. Make sure we add those back
- * instead of leaving them on the local stack list.
- */
- list_splice(&list, &q->timeout_list);
-
- spin_unlock_irqrestore(q->queue_lock, flags);
-
-}
-EXPORT_SYMBOL_GPL(blk_abort_queue);
#include "blk.h"
#include "blk-cgroup.h"
-static struct blkcg_policy blkcg_policy_cfq __maybe_unused;
-
/*
* tunables
*/
return pd ? container_of(pd, struct cfq_group, pd) : NULL;
}
-static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
-{
- return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
-}
-
static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
{
return pd_to_blkg(&cfqg->pd);
#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static struct blkcg_policy blkcg_policy_cfq;
+
+static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
+{
+ return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
+}
+
static inline void cfqg_get(struct cfq_group *cfqg)
{
return blkg_get(cfqg_to_blkg(cfqg));
cfq_shutdown_timer_wq(cfqd);
-#ifndef CONFIG_CFQ_GROUP_IOSCHED
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+ blkcg_deactivate_policy(q, &blkcg_policy_cfq);
+#else
kfree(cfqd->root_group);
#endif
- blkcg_deactivate_policy(q, &blkcg_policy_cfq);
kfree(cfqd);
}
#ifdef CONFIG_CFQ_GROUP_IOSCHED
if (!cfq_group_idle)
cfq_group_idle = 1;
-#else
- cfq_group_idle = 0;
-#endif
ret = blkcg_policy_register(&blkcg_policy_cfq);
if (ret)
return ret;
+#else
+ cfq_group_idle = 0;
+#endif
+ ret = -ENOMEM;
cfq_pool = KMEM_CACHE(cfq_queue, 0);
if (!cfq_pool)
goto err_pol_unreg;
err_free_pool:
kmem_cache_destroy(cfq_pool);
err_pol_unreg:
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
return ret;
}
static void __exit cfq_exit(void)
{
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
elv_unregister(&iosched_cfq);
kmem_cache_destroy(cfq_pool);
}
break;
}
+ if (capable(CAP_SYS_RAWIO))
+ return 0;
+
/* In particular, rule out all resets and host-specific ioctls. */
printk_ratelimited(KERN_WARNING
"%s: sending ioctl %x to a partition!\n", current->comm, cmd);
- return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
EXPORT_SYMBOL(scsi_verify_blk_ioctl);
return_ACPI_STATUS(status);
}
- if (sleep_state != ACPI_STATE_S5) {
- /*
- * Disable BM arbitration. This feature is contained within an
- * optional register (PM2 Control), so ignore a BAD_ADDRESS
- * exception.
- */
- status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
- if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
- return_ACPI_STATUS(status);
- }
- }
-
/*
* 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
[ACPI_EVENT_POWER_BUTTON].
status_register_id, ACPI_CLEAR_STATUS);
- /*
- * Enable BM arbitration. This feature is contained within an
- * optional register (PM2 Control), so ignore a BAD_ADDRESS
- * exception.
- */
- status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
- if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
- return_ACPI_STATUS(status);
- }
-
acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
return_ACPI_STATUS(status);
}
/* Create the new outer package and populate it */
status =
- acpi_ns_wrap_with_package(data, *elements,
+ acpi_ns_wrap_with_package(data, return_object,
return_object_ptr);
if (ACPI_FAILURE(status)) {
return (status);
* Processor (CPU3, 0x03, 0x00000410, 0x06) {}
* }
*
- * Ignores apic_id and always return 0 for CPU0's handle.
+ * Ignores apic_id and always returns 0 for the processor
+ * handle with acpi id 0 if nr_cpu_ids is 1.
+ * This should be the case if SMP tables are not found.
* Return -1 for other CPU's handle.
*/
- if (acpi_id == 0)
+ if (nr_cpu_ids <= 1 && acpi_id == 0)
return acpi_id;
else
return apic_id;
first_word = 0;
spin_lock_irq(&b->bm_lock);
}
-
/* last page (respectively only page, for first page == last page) */
last_word = MLPP(el >> LN2_BPL);
- bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+
+ /* consider bitmap->bm_bits = 32768, bitmap->bm_number_of_pages = 1. (or multiples).
+ * ==> e = 32767, el = 32768, last_page = 2,
+ * and now last_word = 0.
+ * We do not want to touch last_page in this case,
+ * as we did not allocate it, it is not present in bitmap->bm_pages.
+ */
+ if (last_word)
+ bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
/* possibly trailing bits.
* example: (e & 63) == 63, el will be e+1.
req->rq_state |= RQ_LOCAL_COMPLETED;
req->rq_state &= ~RQ_LOCAL_PENDING;
- D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+ if (req->rq_state & RQ_LOCAL_ABORTED) {
+ _req_may_be_done(req, m);
+ break;
+ }
__drbd_chk_io_error(mdev, false);
goto_queue_for_net_read:
+ D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+
/* no point in retrying if there is no good remote data,
* or we have no connection. */
if (mdev->state.pdsk != D_UP_TO_DATE) {
return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
}
+static void maybe_pull_ahead(struct drbd_conf *mdev)
+{
+ int congested = 0;
+
+ /* If I don't even have good local storage, we can not reasonably try
+ * to pull ahead of the peer. We also need the local reference to make
+ * sure mdev->act_log is there.
+ * Note: caller has to make sure that net_conf is there.
+ */
+ if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ return;
+
+ if (mdev->net_conf->cong_fill &&
+ atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
+ dev_info(DEV, "Congestion-fill threshold reached\n");
+ congested = 1;
+ }
+
+ if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
+ dev_info(DEV, "Congestion-extents threshold reached\n");
+ congested = 1;
+ }
+
+ if (congested) {
+ queue_barrier(mdev); /* last barrier, after mirrored writes */
+
+ if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
+ _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
+ else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
+ _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
+ }
+ put_ldev(mdev);
+}
+
static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
{
const int rw = bio_rw(bio);
_req_mod(req, queue_for_send_oos);
if (remote &&
- mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) {
- int congested = 0;
-
- if (mdev->net_conf->cong_fill &&
- atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
- dev_info(DEV, "Congestion-fill threshold reached\n");
- congested = 1;
- }
-
- if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
- dev_info(DEV, "Congestion-extents threshold reached\n");
- congested = 1;
- }
-
- if (congested) {
- queue_barrier(mdev); /* last barrier, after mirrored writes */
-
- if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
- _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
- else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
- _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
- }
- }
+ mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
+ maybe_pull_ahead(mdev);
spin_unlock_irq(&mdev->req_lock);
kfree(b); /* if someone else has beaten us to it... */
if (drive == current_reqD)
drive = current_drive;
+ __cancel_delayed_work(&fd_timeout);
if (drive < 0 || drive >= N_DRIVE) {
delay = 20UL * HZ;
struct gendisk *disk;
int err;
+ err = -ENOMEM;
lo = kzalloc(sizeof(*lo), GFP_KERNEL);
- if (!lo) {
- err = -ENOMEM;
+ if (!lo)
goto out;
- }
- err = idr_pre_get(&loop_index_idr, GFP_KERNEL);
- if (err < 0)
+ if (!idr_pre_get(&loop_index_idr, GFP_KERNEL))
goto out_free_dev;
if (i >= 0) {
#include <linux/kthread.h>
#include <../drivers/ata/ahci.h>
#include <linux/export.h>
+#include <linux/debugfs.h>
#include "mtip32xx.h"
#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32)
* allocated in mtip_init().
*/
static int mtip_major;
+static struct dentry *dfs_parent;
static DEFINE_SPINLOCK(rssd_index_lock);
static DEFINE_IDA(rssd_index_ida);
}
/*
- * Sysfs register/status dump.
+ * Sysfs status dump.
*
* @dev Pointer to the device structure, passed by the kernrel.
* @attr Pointer to the device_attribute structure passed by the kernel.
* return value
* The size, in bytes, of the data copied into buf.
*/
-static ssize_t mtip_hw_show_registers(struct device *dev,
+static ssize_t mtip_hw_show_status(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- u32 group_allocated;
struct driver_data *dd = dev_to_disk(dev)->private_data;
int size = 0;
+
+ if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
+ size += sprintf(buf, "%s", "thermal_shutdown\n");
+ else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
+ size += sprintf(buf, "%s", "write_protect\n");
+ else
+ size += sprintf(buf, "%s", "online\n");
+
+ return size;
+}
+
+static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
+
+static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
+ size_t len, loff_t *offset)
+{
+ struct driver_data *dd = (struct driver_data *)f->private_data;
+ char buf[MTIP_DFS_MAX_BUF_SIZE];
+ u32 group_allocated;
+ int size = *offset;
int n;
- size += sprintf(&buf[size], "Hardware\n--------\n");
- size += sprintf(&buf[size], "S ACTive : [ 0x");
+ if (!len || size)
+ return 0;
+
+ if (size < 0)
+ return -EINVAL;
+
+ size += sprintf(&buf[size], "H/ S ACTive : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ",
readl(dd->port->s_active[n]));
size += sprintf(&buf[size], "]\n");
- size += sprintf(&buf[size], "Command Issue : [ 0x");
+ size += sprintf(&buf[size], "H/ Command Issue : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ",
readl(dd->port->cmd_issue[n]));
size += sprintf(&buf[size], "]\n");
- size += sprintf(&buf[size], "Completed : [ 0x");
+ size += sprintf(&buf[size], "H/ Completed : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ",
readl(dd->port->completed[n]));
size += sprintf(&buf[size], "]\n");
- size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n",
+ size += sprintf(&buf[size], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
readl(dd->port->mmio + PORT_IRQ_STAT));
- size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n",
+ size += sprintf(&buf[size], "H/ HOST IRQ STAT : [ 0x%08X ]\n",
readl(dd->mmio + HOST_IRQ_STAT));
size += sprintf(&buf[size], "\n");
- size += sprintf(&buf[size], "Local\n-----\n");
- size += sprintf(&buf[size], "Allocated : [ 0x");
+ size += sprintf(&buf[size], "L/ Allocated : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) {
if (sizeof(long) > sizeof(u32))
}
size += sprintf(&buf[size], "]\n");
- size += sprintf(&buf[size], "Commands in Q: [ 0x");
+ size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) {
if (sizeof(long) > sizeof(u32))
}
size += sprintf(&buf[size], "]\n");
- return size;
+ *offset = size <= len ? size : len;
+ size = copy_to_user(ubuf, buf, *offset);
+ if (size)
+ return -EFAULT;
+
+ return *offset;
}
-static ssize_t mtip_hw_show_status(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
+ size_t len, loff_t *offset)
{
- struct driver_data *dd = dev_to_disk(dev)->private_data;
- int size = 0;
+ struct driver_data *dd = (struct driver_data *)f->private_data;
+ char buf[MTIP_DFS_MAX_BUF_SIZE];
+ int size = *offset;
- if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
- size += sprintf(buf, "%s", "thermal_shutdown\n");
- else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
- size += sprintf(buf, "%s", "write_protect\n");
- else
- size += sprintf(buf, "%s", "online\n");
-
- return size;
-}
+ if (!len || size)
+ return 0;
-static ssize_t mtip_hw_show_flags(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct driver_data *dd = dev_to_disk(dev)->private_data;
- int size = 0;
+ if (size < 0)
+ return -EINVAL;
- size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n",
+ size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
dd->port->flags);
- size += sprintf(&buf[size], "Flag in dd struct : [ %08lX ]\n",
+ size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n",
dd->dd_flag);
- return size;
+ *offset = size <= len ? size : len;
+ size = copy_to_user(ubuf, buf, *offset);
+ if (size)
+ return -EFAULT;
+
+ return *offset;
}
-static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL);
-static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
-static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL);
+static const struct file_operations mtip_regs_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = mtip_hw_read_registers,
+ .llseek = no_llseek,
+};
+
+static const struct file_operations mtip_flags_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = mtip_hw_read_flags,
+ .llseek = no_llseek,
+};
/*
* Create the sysfs related attributes.
if (!kobj || !dd)
return -EINVAL;
- if (sysfs_create_file(kobj, &dev_attr_registers.attr))
- dev_warn(&dd->pdev->dev,
- "Error creating 'registers' sysfs entry\n");
if (sysfs_create_file(kobj, &dev_attr_status.attr))
dev_warn(&dd->pdev->dev,
"Error creating 'status' sysfs entry\n");
- if (sysfs_create_file(kobj, &dev_attr_flags.attr))
- dev_warn(&dd->pdev->dev,
- "Error creating 'flags' sysfs entry\n");
return 0;
}
if (!kobj || !dd)
return -EINVAL;
- sysfs_remove_file(kobj, &dev_attr_registers.attr);
sysfs_remove_file(kobj, &dev_attr_status.attr);
- sysfs_remove_file(kobj, &dev_attr_flags.attr);
return 0;
}
+static int mtip_hw_debugfs_init(struct driver_data *dd)
+{
+ if (!dfs_parent)
+ return -1;
+
+ dd->dfs_node = debugfs_create_dir(dd->disk->disk_name, dfs_parent);
+ if (IS_ERR_OR_NULL(dd->dfs_node)) {
+ dev_warn(&dd->pdev->dev,
+ "Error creating node %s under debugfs\n",
+ dd->disk->disk_name);
+ dd->dfs_node = NULL;
+ return -1;
+ }
+
+ debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd,
+ &mtip_flags_fops);
+ debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd,
+ &mtip_regs_fops);
+
+ return 0;
+}
+
+static void mtip_hw_debugfs_exit(struct driver_data *dd)
+{
+ debugfs_remove_recursive(dd->dfs_node);
+}
+
+
/*
* Perform any init/resume time hardware setup
*
mtip_hw_sysfs_init(dd, kobj);
kobject_put(kobj);
}
+ mtip_hw_debugfs_init(dd);
if (dd->mtip_svc_handler) {
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
return rv;
kthread_run_error:
+ mtip_hw_debugfs_exit(dd);
+
/* Delete our gendisk. This also removes the device from /dev */
del_gendisk(dd->disk);
kobject_put(kobj);
}
}
+ mtip_hw_debugfs_exit(dd);
/*
* Delete our gendisk structure. This also removes the device
}
mtip_major = error;
+ if (!dfs_parent) {
+ dfs_parent = debugfs_create_dir("rssd", NULL);
+ if (IS_ERR_OR_NULL(dfs_parent)) {
+ printk(KERN_WARNING "Error creating debugfs parent\n");
+ dfs_parent = NULL;
+ }
+ }
+
/* Register our PCI operations. */
error = pci_register_driver(&mtip_pci_driver);
- if (error)
+ if (error) {
+ debugfs_remove(dfs_parent);
unregister_blkdev(mtip_major, MTIP_DRV_NAME);
+ }
return error;
}
*/
static void __exit mtip_exit(void)
{
+ debugfs_remove_recursive(dfs_parent);
+
/* Release the allocated major block device number. */
unregister_blkdev(mtip_major, MTIP_DRV_NAME);
#include <linux/ata.h>
#include <linux/interrupt.h>
#include <linux/genhd.h>
-#include <linux/version.h>
/* Offset of Subsystem Device ID in pci confoguration space */
#define PCI_SUBSYSTEM_DEVICEID 0x2E
#define dbg_printk(format, arg...)
#endif
+#define MTIP_DFS_MAX_BUF_SIZE 1024
+
#define __force_bit2int (unsigned int __force)
enum {
unsigned long dd_flag; /* NOTE: use atomic bit operations on this */
struct task_struct *mtip_svc_handler; /* task_struct of svc thd */
+
+ struct dentry *dfs_node;
};
#endif
}
}
+struct mm_plug_cb {
+ struct blk_plug_cb cb;
+ struct cardinfo *card;
+};
+
+static void mm_unplug(struct blk_plug_cb *cb)
+{
+ struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb);
+
+ spin_lock_irq(&mmcb->card->lock);
+ activate(mmcb->card);
+ spin_unlock_irq(&mmcb->card->lock);
+ kfree(mmcb);
+}
+
+static int mm_check_plugged(struct cardinfo *card)
+{
+ struct blk_plug *plug = current->plug;
+ struct mm_plug_cb *mmcb;
+
+ if (!plug)
+ return 0;
+
+ list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
+ if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
+ return 1;
+ }
+ /* Not currently on the callback list */
+ mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
+ if (!mmcb)
+ return 0;
+
+ mmcb->card = card;
+ mmcb->cb.callback = mm_unplug;
+ list_add(&mmcb->cb.list, &plug->cb_list);
+ return 1;
+}
+
static void mm_make_request(struct request_queue *q, struct bio *bio)
{
struct cardinfo *card = q->queuedata;
*card->biotail = bio;
bio->bi_next = NULL;
card->biotail = &bio->bi_next;
+ if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card))
+ activate(card);
spin_unlock_irq(&card->lock);
return;
break;
case BLKIF_OP_DISCARD:
dst->u.discard.flag = src->u.discard.flag;
+ dst->u.discard.id = src->u.discard.id;
dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
break;
case BLKIF_OP_DISCARD:
dst->u.discard.flag = src->u.discard.flag;
+ dst->u.discard.id = src->u.discard.id;
dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
return free;
}
-static void add_id_to_freelist(struct blkfront_info *info,
+static int add_id_to_freelist(struct blkfront_info *info,
unsigned long id)
{
+ if (info->shadow[id].req.u.rw.id != id)
+ return -EINVAL;
+ if (info->shadow[id].request == NULL)
+ return -EINVAL;
info->shadow[id].req.u.rw.id = info->shadow_free;
info->shadow[id].request = NULL;
info->shadow_free = id;
+ return 0;
}
+static const char *op_name(int op)
+{
+ static const char *const names[] = {
+ [BLKIF_OP_READ] = "read",
+ [BLKIF_OP_WRITE] = "write",
+ [BLKIF_OP_WRITE_BARRIER] = "barrier",
+ [BLKIF_OP_FLUSH_DISKCACHE] = "flush",
+ [BLKIF_OP_DISCARD] = "discard" };
+
+ if (op < 0 || op >= ARRAY_SIZE(names))
+ return "unknown";
+
+ if (!names[op])
+ return "reserved";
+
+ return names[op];
+}
static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
{
unsigned int end = minor + nr;
bret = RING_GET_RESPONSE(&info->ring, i);
id = bret->id;
+ /*
+ * The backend has messed up and given us an id that we would
+ * never have given to it (we stamp it up to BLK_RING_SIZE -
+ * look in get_id_from_freelist.
+ */
+ if (id >= BLK_RING_SIZE) {
+ WARN(1, "%s: response to %s has incorrect id (%ld)\n",
+ info->gd->disk_name, op_name(bret->operation), id);
+ /* We can't safely get the 'struct request' as
+ * the id is busted. */
+ continue;
+ }
req = info->shadow[id].request;
if (bret->operation != BLKIF_OP_DISCARD)
blkif_completion(&info->shadow[id]);
- add_id_to_freelist(info, id);
+ if (add_id_to_freelist(info, id)) {
+ WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
+ info->gd->disk_name, op_name(bret->operation), id);
+ continue;
+ }
error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
switch (bret->operation) {
case BLKIF_OP_DISCARD:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
struct request_queue *rq = info->rq;
- printk(KERN_WARNING "blkfront: %s: discard op failed\n",
- info->gd->disk_name);
+ printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+ info->gd->disk_name, op_name(bret->operation));
error = -EOPNOTSUPP;
info->feature_discard = 0;
info->feature_secdiscard = 0;
case BLKIF_OP_FLUSH_DISKCACHE:
case BLKIF_OP_WRITE_BARRIER:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
- printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
- info->flush_op == BLKIF_OP_WRITE_BARRIER ?
- "barrier" : "flush disk cache",
- info->gd->disk_name);
+ printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+ info->gd->disk_name, op_name(bret->operation));
error = -EOPNOTSUPP;
}
if (unlikely(bret->status == BLKIF_RSP_ERROR &&
info->shadow[id].req.u.rw.nr_segments == 0)) {
- printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
- info->flush_op == BLKIF_OP_WRITE_BARRIER ?
- "barrier" : "flush disk cache",
- info->gd->disk_name);
+ printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
+ info->gd->disk_name, op_name(bret->operation));
error = -EOPNOTSUPP;
}
if (unlikely(error)) {
old_parent = clk->parent;
- /* find index of new parent clock using cached parent ptrs */
- if (clk->parents)
- for (i = 0; i < clk->num_parents; i++)
- if (clk->parents[i] == parent)
- break;
- else
+ if (!clk->parents)
clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
/*
- * find index of new parent clock using string name comparison
- * also try to cache the parent to avoid future calls to __clk_lookup
+ * find index of new parent clock using cached parent ptrs,
+ * or if not yet cached, use string name comparison and cache
+ * them now to avoid future calls to __clk_lookup.
*/
- if (i == clk->num_parents)
- for (i = 0; i < clk->num_parents; i++)
- if (!strcmp(clk->parent_names[i], parent->name)) {
- if (clk->parents)
- clk->parents[i] = __clk_lookup(parent->name);
- break;
- }
+ for (i = 0; i < clk->num_parents; i++) {
+ if (clk->parents && clk->parents[i] == parent)
+ break;
+ else if (!strcmp(clk->parent_names[i], parent->name)) {
+ if (clk->parents)
+ clk->parents[i] = __clk_lookup(parent->name);
+ break;
+ }
+ }
if (i == clk->num_parents) {
pr_debug("%s: clock %s is not a possible parent of clock %s\n",
config GPIO_MSM_V1
tristate "Qualcomm MSM GPIO v1"
- depends on GPIOLIB && ARCH_MSM
+ depends on GPIOLIB && ARCH_MSM && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
help
Say yes here to support the GPIO interface on ARM v6 based
Qualcomm MSM chips. Most of the pins on the MSM can be
return 0;
}
+EXPORT_SYMBOL(devm_gpio_request_one);
/**
* devm_gpio_free - free an interrupt
writel(~0, port->base + GPIO_ISR);
if (mxc_gpio_hwtype == IMX21_GPIO) {
- /* setup one handler for all GPIO interrupts */
- if (pdev->id == 0)
- irq_set_chained_handler(port->irq,
- mx2_gpio_irq_handler);
+ /*
+ * Setup one handler for all GPIO interrupts. Actually setting
+ * the handler is needed only once, but doing it for every port
+ * is more robust and easier.
+ */
+ irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
} else {
/* setup one handler for each entry */
irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);
if (bank->dbck_enable_mask && !bank->dbck_enabled) {
clk_enable(bank->dbck);
bank->dbck_enabled = true;
+
+ __raw_writel(bank->dbck_enable_mask,
+ bank->base + bank->regs->debounce_en);
}
}
static inline void _gpio_dbck_disable(struct gpio_bank *bank)
{
if (bank->dbck_enable_mask && bank->dbck_enabled) {
+ /*
+ * Disable debounce before cutting it's clock. If debounce is
+ * enabled but the clock is not, GPIO module seems to be unable
+ * to detect events and generate interrupts at least on OMAP3.
+ */
+ __raw_writel(0, bank->base + bank->regs->debounce_en);
+
clk_disable(bank->dbck);
bank->dbck_enabled = false;
}
bank->is_mpuio = pdata->is_mpuio;
bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
bank->loses_context = pdata->loses_context;
- bank->get_context_loss_count = pdata->get_context_loss_count;
bank->regs = pdata->regs;
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
omap_gpio_chip_init(bank);
omap_gpio_show_rev(bank);
+ if (bank->loses_context)
+ bank->get_context_loss_count = pdata->get_context_loss_count;
+
pm_runtime_put(bank->dev);
list_add_tail(&bank->node, &omap_gpio_list);
}
spin_lock_init(&chip->lock);
gsta_gpio_setup(chip);
- for (i = 0; i < GSTA_NR_GPIO; i++)
- gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
+ if (gpio_pdata)
+ for (i = 0; i < GSTA_NR_GPIO; i++)
+ gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
/* 384 was used in previous code: be compatible for other drivers */
err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE);
tps65910_gpio->gpio_chip.set = tps65910_gpio_set;
tps65910_gpio->gpio_chip.get = tps65910_gpio_get;
tps65910_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+ tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node;
+#endif
if (pdata && pdata->gpio_base)
tps65910_gpio->gpio_chip.base = pdata->gpio_base;
else
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+ if (value)
+ value = WM8994_GPN_LVL;
+
return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
- WM8994_GPN_DIR, 0);
+ WM8994_GPN_DIR | WM8994_GPN_LVL, value);
}
static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
return true;
}
+static bool valid_inferred_mode(const struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ struct drm_display_mode *m;
+ bool ok = false;
+
+ list_for_each_entry(m, &connector->probed_modes, head) {
+ if (mode->hdisplay == m->hdisplay &&
+ mode->vdisplay == m->vdisplay &&
+ drm_mode_vrefresh(mode) == drm_mode_vrefresh(m))
+ return false; /* duplicated */
+ if (mode->hdisplay <= m->hdisplay &&
+ mode->vdisplay <= m->vdisplay)
+ ok = true;
+ }
+ return ok;
+}
+
static int
drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
struct detailed_timing *timing)
struct drm_device *dev = connector->dev;
for (i = 0; i < drm_num_dmt_modes; i++) {
- if (mode_in_range(drm_dmt_modes + i, edid, timing)) {
+ if (mode_in_range(drm_dmt_modes + i, edid, timing) &&
+ valid_inferred_mode(connector, drm_dmt_modes + i)) {
newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
if (newmode) {
drm_mode_probed_add(connector, newmode);
return modes;
fixup_mode_1366x768(newmode);
- if (!mode_in_range(newmode, edid, timing)) {
+ if (!mode_in_range(newmode, edid, timing) ||
+ !valid_inferred_mode(connector, newmode)) {
drm_mode_destroy(dev, newmode);
continue;
}
return modes;
fixup_mode_1366x768(newmode);
- if (!mode_in_range(newmode, edid, timing)) {
+ if (!mode_in_range(newmode, edid, timing) ||
+ !valid_inferred_mode(connector, newmode)) {
drm_mode_destroy(dev, newmode);
continue;
}
}
}
+static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
+{
+ struct apertures_struct *ap;
+ struct pci_dev *pdev = dev_priv->dev->pdev;
+ bool primary;
+
+ ap = alloc_apertures(1);
+ if (!ap)
+ return;
+
+ ap->ranges[0].base = dev_priv->dev->agp->base;
+ ap->ranges[0].size =
+ dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+ primary =
+ pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+
+ remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
+
+ kfree(ap);
+}
+
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
goto free_priv;
}
+ dev_priv->mm.gtt = intel_gtt_get();
+ if (!dev_priv->mm.gtt) {
+ DRM_ERROR("Failed to initialize GTT\n");
+ ret = -ENODEV;
+ goto put_bridge;
+ }
+
+ i915_kick_out_firmware_fb(dev_priv);
+
pci_set_master(dev->pdev);
/* overlay on gen2 is broken and can't address above 1G */
goto put_bridge;
}
- dev_priv->mm.gtt = intel_gtt_get();
- if (!dev_priv->mm.gtt) {
- DRM_ERROR("Failed to initialize GTT\n");
- ret = -ENODEV;
- goto out_rmmap;
- }
-
aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
dev_priv->mm.gtt_mapping =
rdev->vm_manager.enabled = false;
/* mark first vm as always in use, it's the system one */
+ /* allocate enough for 2 full VM pts */
r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
- rdev->vm_manager.max_pfn * 8,
+ rdev->vm_manager.max_pfn * 8 * 2,
RADEON_GEM_DOMAIN_VRAM);
if (r) {
dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n",
mutex_init(&vm->mutex);
INIT_LIST_HEAD(&vm->list);
INIT_LIST_HEAD(&vm->va);
- vm->last_pfn = 0;
+ /* SI requires equal sized PTs for all VMs, so always set
+ * last_pfn to max_pfn. cayman allows variable sized
+ * pts so we can grow then as needed. Once we switch
+ * to two level pts we can unify this again.
+ */
+ if (rdev->family >= CHIP_TAHITI)
+ vm->last_pfn = rdev->vm_manager.max_pfn;
+ else
+ vm->last_pfn = 0;
/* map the ib pool buffer at 0 in virtual address space, set
* read only
*/
int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
+ struct radeon_device *rdev = dev->dev_private;
struct drm_radeon_gem_busy *args = data;
struct drm_gem_object *gobj;
struct radeon_bo *robj;
break;
}
drm_gem_object_unreference_unlocked(gobj);
- r = radeon_gem_handle_lockup(robj->rdev, r);
+ r = radeon_gem_handle_lockup(rdev, r);
return r;
}
int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
+ struct radeon_device *rdev = dev->dev_private;
struct drm_radeon_gem_wait_idle *args = data;
struct drm_gem_object *gobj;
struct radeon_bo *robj;
robj = gem_to_radeon_bo(gobj);
r = radeon_bo_wait(robj, NULL, false);
/* callback hw specific functions if any */
- if (robj->rdev->asic->ioctl_wait_idle)
- robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj);
+ if (rdev->asic->ioctl_wait_idle)
+ robj->rdev->asic->ioctl_wait_idle(rdev, robj);
drm_gem_object_unreference_unlocked(gobj);
- r = radeon_gem_handle_lockup(robj->rdev, r);
+ r = radeon_gem_handle_lockup(rdev, r);
return r;
}
WREG32(0x15DC, 0);
/* empty context1-15 */
- /* FIXME start with 1G, once using 2 level pt switch to full
+ /* FIXME start with 4G, once using 2 level pt switch to full
* vm size space
*/
/* set vm size, must be a multiple of 4 */
WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
- WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, (1 << 30) / RADEON_GPU_PAGE_SIZE);
+ WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
for (i = 1; i < 16; i++) {
if (i < 8)
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006
#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007
+#define USB_VENDOR_ID_MADCATZ 0x0738
+#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
+
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
/* Start monitoring */
it87_write_value(data, IT87_REG_CONFIG,
- (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
+ (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
| (update_vbat ? 0x41 : 0x01));
}
spin_lock_init(&hwlock->lock);
hwlock->bank = bank;
- ret = hwspin_lock_register_single(hwlock, i);
+ ret = hwspin_lock_register_single(hwlock, base_id + i);
if (ret)
goto reg_failed;
}
reg_failed:
while (--i >= 0)
- hwspin_lock_unregister_single(i);
+ hwspin_lock_unregister_single(base_id + i);
return ret;
}
EXPORT_SYMBOL_GPL(hwspin_lock_register);
error = request_threaded_irq(as5011->button_irq,
NULL, as5011_button_interrupt,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"as5011_button", as5011);
if (error < 0) {
dev_err(&client->dev,
error = request_threaded_irq(as5011->axis_irq, NULL,
as5011_axis_interrupt,
- plat_data->axis_irqflags,
+ plat_data->axis_irqflags | IRQF_ONESHOT,
"as5011_joystick", as5011);
if (error) {
dev_err(&client->dev,
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
+ { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+ { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
};
XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
+ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
- XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
+ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
+ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
{ }
};
}
error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
- IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->dev.driver->name, data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem;
error = request_threaded_irq(client->irq, NULL,
mpr_touchkey_interrupt,
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->dev.driver->name, mpr121);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
msleep(QT1070_RESET_TIME);
err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
- IRQF_TRIGGER_NONE, client->dev.driver->name, data);
+ IRQF_TRIGGER_NONE | IRQF_ONESHOT,
+ client->dev.driver->name, data);
if (err) {
dev_err(&client->dev, "fail to request irq\n");
goto err_free_mem;
error = request_threaded_irq(chip->irqnum, NULL,
tca6416_keys_isr,
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
"tca6416-keypad", chip);
if (error) {
dev_dbg(&client->dev,
client->irq = gpio_to_irq(client->irq);
error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler,
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, keypad_data);
if (error) {
dev_dbg(&client->dev,
goto error_clk;
}
- error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0,
- dev_name(dev), kp);
+ error = request_threaded_irq(kp->irq_press, NULL, keypad_irq,
+ IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad press key irq\n");
goto error_irq_press;
}
- error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0,
- dev_name(dev), kp);
+ error = request_threaded_irq(kp->irq_release, NULL, keypad_irq,
+ IRQF_ONESHOT, dev_name(dev), kp);
if (error < 0) {
dev_err(kp->dev, "Could not allocate keypad release key irq\n");
goto error_irq_release;
struct ad714x_platform_data *plat_data = dev->platform_data;
struct ad714x_chip *ad714x;
void *drv_mem;
+ unsigned long irqflags;
struct ad714x_button_drv *bt_drv;
struct ad714x_slider_drv *sd_drv;
alloc_idx++;
}
+ irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING;
+ irqflags |= IRQF_ONESHOT;
+
error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
- plat_data->irqflags ?
- plat_data->irqflags : IRQF_TRIGGER_FALLING,
- "ad714x_captouch", ad714x);
+ irqflags, "ad714x_captouch", ad714x);
if (error) {
dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
goto err_unreg_dev;
/* REVISIT: flush the event queue? */
status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
- IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&pdev->dev), keys);
if (status < 0)
goto fail2;
#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252
#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253
#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254
+/* MacbookPro10,1 (unibody, June 2012) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
+ /* MacbookPro10,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
/* Terminating entry */
{}
};
{ DIM_X, DIM_X / SN_COORD, -4620, 5140 },
{ DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING7_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+ },
{}
};
rep_data[0] = 12;
result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
- rep_data[0], &rep_data, 2,
+ rep_data[0], rep_data, 2,
WAC_MSG_RETRIES);
if (result >= 0 && rep_data[1] > 2)
break;
case HID_USAGE_CONTACTMAX:
- wacom_retrieve_report_data(intf, features);
+ /* leave touch_max as is if predefined */
+ if (!features->touch_max)
+ wacom_retrieve_report_data(intf, features);
i++;
break;
}
AD7879_TMR(ts->pen_down_acc_interval);
err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(dev), ts);
if (err) {
dev_err(dev, "irq %d busy?\n", ts->irq);
goto err_free_object;
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
- pdata->irqflags, client->dev.driver->name, data);
+ pdata->irqflags | IRQF_ONESHOT,
+ client->dev.driver->name, data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_object;
input_set_drvdata(in_dev, bu21013_data);
error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
- IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED |
+ IRQF_ONESHOT,
DRIVER_TP, bu21013_data);
if (error) {
dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
}
err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
- IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "touch_reset_key", ts);
if (err < 0) {
dev_err(&client->dev,
"irq %d busy? error %d\n", client->irq, err);
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
- 0, "mrstouch", tsdev);
+ IRQF_ONESHOT, "mrstouch", tsdev);
if (err) {
dev_err(tsdev->dev, "unable to allocate irq\n");
goto err_free_mem;
input_set_drvdata(input, tsdata);
error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
- IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto error_clk;
}
- error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
+ error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT,
dev_name(dev), ts);
if (error < 0) {
dev_err(ts->dev, "Could not allocate ts irq\n");
tsc2005_stop_scan(ts);
error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
- IRQF_TRIGGER_RISING, "tsc2005", ts);
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "tsc2005", ts);
if (error) {
dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
goto err_free_mem;
static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
int amd_iommu_max_glx_val = -1;
+static struct dma_map_ops amd_iommu_dma_ops;
+
/*
* general struct to manage commands send to an IOMMU
*/
return;
de_fflush = debugfs_create_bool("fullflush", 0444, stats_dir,
- (u32 *)&amd_iommu_unmap_flush);
+ &amd_iommu_unmap_flush);
amd_iommu_stats_add(&compl_wait);
amd_iommu_stats_add(&cnt_map_single);
list_add_tail(&dma_domain->list, &iommu_pd_list);
spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
+ dev_data = get_dev_data(dev);
+
+ if (!dev_data->passthrough)
+ dev->archdata.dma_ops = &amd_iommu_dma_ops;
+ else
+ dev->archdata.dma_ops = &nommu_dma_ops;
+
break;
case BUS_NOTIFY_DEL_DEVICE:
to handle */
LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings
we find in ACPI */
-bool amd_iommu_unmap_flush; /* if true, flush on every unmap */
+u32 amd_iommu_unmap_flush; /* if true, flush on every unmap */
LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
system */
amd_iommu_init_api();
+ x86_platform.iommu_shutdown = disable_iommus;
+
if (iommu_pass_through)
goto out;
else
printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n");
- x86_platform.iommu_shutdown = disable_iommus;
-
out:
return ret;
* If true, the addresses will be flushed on unmap time, not when
* they are reused
*/
-extern bool amd_iommu_unmap_flush;
+extern u32 amd_iommu_unmap_flush;
/* Smallest number of PASIDs supported by any IOMMU in the system */
extern u32 amd_iommu_max_pasids;
return 0;
as->pte_count = devm_kzalloc(smmu->dev,
- sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_KERNEL);
+ sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_ATOMIC);
if (!as->pte_count) {
dev_err(smmu->dev,
"failed to allocate smmu_device PTE cunters\n");
return -ENOMEM;
}
- as->pdir_page = alloc_page(GFP_KERNEL | __GFP_DMA);
+ as->pdir_page = alloc_page(GFP_ATOMIC | __GFP_DMA);
if (!as->pdir_page) {
dev_err(smmu->dev,
"failed to allocate smmu_device page directory\n");
#include <linux/reboot.h>
#include "leds.h"
+static int panic_heartbeats;
+
struct heartbeat_trig_data {
unsigned int phase;
unsigned int period;
unsigned long brightness = LED_OFF;
unsigned long delay = 0;
+ if (unlikely(panic_heartbeats)) {
+ led_set_brightness(led_cdev, LED_OFF);
+ return;
+ }
+
/* acts like an actual heart beat -- ie thump-thump-pause... */
switch (heartbeat_data->phase) {
case 0:
return NOTIFY_DONE;
}
+static int heartbeat_panic_notifier(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+ panic_heartbeats = 1;
+ return NOTIFY_DONE;
+}
+
static struct notifier_block heartbeat_reboot_nb = {
.notifier_call = heartbeat_reboot_notifier,
};
static struct notifier_block heartbeat_panic_nb = {
- .notifier_call = heartbeat_reboot_notifier,
+ .notifier_call = heartbeat_panic_notifier,
};
static int __init heartbeat_trig_init(void)
if (r)
return r;
+ r = dm_pool_commit_metadata(pool->pmd);
+ if (r) {
+ DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
+ __func__, r);
+ return r;
+ }
+
r = dm_pool_reserve_metadata_snap(pool->pmd);
if (r)
DMWARN("reserve_metadata_snap message failed.");
super_types[mddev->major_version].
validate_super(mddev, rdev);
if ((info->state & (1<<MD_DISK_SYNC)) &&
- (!test_bit(In_sync, &rdev->flags) ||
- rdev->raid_disk != info->raid_disk)) {
+ rdev->raid_disk != info->raid_disk) {
/* This was a hot-add request, but events doesn't
* match, so reject it.
*/
thread->tsk = kthread_run(md_thread, thread,
"%s_%s",
mdname(thread->mddev),
- name ?: mddev->pers->name);
+ name);
if (IS_ERR(thread->tsk)) {
kfree(thread);
return NULL;
int skipped = 0;
struct md_rdev *rdev;
char *desc;
+ struct blk_plug plug;
/* just incase thread restarts... */
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
}
mddev->curr_resync_completed = j;
+ blk_start_plug(&plug);
while (j < max_sectors) {
sector_t sectors;
* this also signals 'finished resyncing' to md_stop
*/
out:
+ blk_finish_plug(&plug);
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
/* tell personality that we are finished */
}
{
- mddev->thread = md_register_thread(multipathd, mddev, NULL);
+ mddev->thread = md_register_thread(multipathd, mddev,
+ "multipath");
if (!mddev->thread) {
printk(KERN_ERR "multipath: couldn't allocate thread"
" for %s\n", mdname(mddev));
#include <linux/device-mapper.h>
#include <linux/export.h>
+#include <linux/vmalloc.h>
#ifdef CONFIG_DM_DEBUG_SPACE_MAPS
ca->nr = nr_blocks;
ca->nr_free = nr_blocks;
- ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL);
- if (!ca->counts)
- return -ENOMEM;
+
+ if (!nr_blocks)
+ ca->counts = NULL;
+ else {
+ ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks);
+ if (!ca->counts)
+ return -ENOMEM;
+ }
return 0;
}
+static void ca_destroy(struct count_array *ca)
+{
+ vfree(ca->counts);
+}
+
static int ca_load(struct count_array *ca, struct dm_space_map *sm)
{
int r;
static int ca_extend(struct count_array *ca, dm_block_t extra_blocks)
{
dm_block_t nr_blocks = ca->nr + extra_blocks;
- uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL);
+ uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks);
if (!counts)
return -ENOMEM;
- memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
- kfree(ca->counts);
+ if (ca->counts) {
+ memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
+ ca_destroy(ca);
+ }
ca->nr = nr_blocks;
ca->nr_free += extra_blocks;
ca->counts = counts;
return 0;
}
-static void ca_destroy(struct count_array *ca)
-{
- kfree(ca->counts);
-}
-
/*----------------------------------------------------------------*/
struct sm_checker {
int r;
struct sm_checker *smc;
- if (!sm)
- return NULL;
+ if (IS_ERR_OR_NULL(sm))
+ return ERR_PTR(-EINVAL);
smc = kmalloc(sizeof(*smc), GFP_KERNEL);
if (!smc)
- return NULL;
+ return ERR_PTR(-ENOMEM);
memcpy(&smc->sm, &ops_, sizeof(smc->sm));
r = ca_create(&smc->old_counts, sm);
if (r) {
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
r = ca_create(&smc->counts, sm);
if (r) {
ca_destroy(&smc->old_counts);
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
smc->real_sm = sm;
ca_destroy(&smc->counts);
ca_destroy(&smc->old_counts);
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
r = ca_commit(&smc->old_counts, &smc->counts);
ca_destroy(&smc->counts);
ca_destroy(&smc->old_counts);
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
return &smc->sm;
int r;
struct sm_checker *smc;
- if (!sm)
- return NULL;
+ if (IS_ERR_OR_NULL(sm))
+ return ERR_PTR(-EINVAL);
smc = kmalloc(sizeof(*smc), GFP_KERNEL);
if (!smc)
- return NULL;
+ return ERR_PTR(-ENOMEM);
memcpy(&smc->sm, &ops_, sizeof(smc->sm));
r = ca_create(&smc->old_counts, sm);
if (r) {
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
r = ca_create(&smc->counts, sm);
if (r) {
ca_destroy(&smc->old_counts);
kfree(smc);
- return NULL;
+ return ERR_PTR(r);
}
smc->real_sm = sm;
dm_block_t nr_blocks)
{
struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks);
- return dm_sm_checker_create_fresh(sm);
+ struct dm_space_map *smc;
+
+ if (IS_ERR_OR_NULL(sm))
+ return sm;
+
+ smc = dm_sm_checker_create_fresh(sm);
+ if (IS_ERR(smc))
+ dm_sm_destroy(sm);
+
+ return smc;
}
EXPORT_SYMBOL_GPL(dm_sm_disk_create);
void dm_tm_destroy(struct dm_transaction_manager *tm)
{
+ if (!tm->is_clone)
+ wipe_shadow_table(tm);
+
kfree(tm);
}
EXPORT_SYMBOL_GPL(dm_tm_destroy);
}
*sm = dm_sm_checker_create(inner);
- if (!*sm)
+ if (IS_ERR(*sm)) {
+ r = PTR_ERR(*sm);
goto bad2;
+ }
} else {
r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location,
}
*sm = dm_sm_checker_create(inner);
- if (!*sm)
+ if (IS_ERR(*sm)) {
+ r = PTR_ERR(*sm);
goto bad2;
+ }
}
return 0;
int bad_sectors;
int disk = start_disk + i;
- if (disk >= conf->raid_disks)
- disk -= conf->raid_disks;
+ if (disk >= conf->raid_disks * 2)
+ disk -= conf->raid_disks * 2;
rdev = rcu_dereference(conf->mirrors[disk].rdev);
if (r1_bio->bios[disk] == IO_BLOCKED
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
struct md_rdev *blocked_rdev;
- int plugged;
int first_clone;
int sectors_handled;
int max_sectors;
* the bad blocks. Each set of writes gets it's own r1bio
* with a set of bios attached.
*/
- plugged = mddev_check_plugged(mddev);
disks = conf->raid_disks * 2;
retry_write:
bio_list_add(&conf->pending_bio_list, mbio);
conf->pending_count++;
spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (!mddev_check_plugged(mddev))
+ md_wakeup_thread(mddev->thread);
}
/* Mustn't call r1_bio_write_done before this next test,
* as it could result in the bio being freed.
/* In case raid1d snuck in to freeze_array */
wake_up(&conf->wait_barrier);
-
- if (do_sync || !bitmap || !plugged)
- md_wakeup_thread(mddev->thread);
}
static void status(struct seq_file *seq, struct mddev *mddev)
*/
if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
atomic_set(&r1_bio->remaining, read_targets);
- for (i = 0; i < conf->raid_disks * 2; i++) {
+ for (i = 0; i < conf->raid_disks * 2 && read_targets; i++) {
bio = r1_bio->bios[i];
if (bio->bi_end_io == end_sync_read) {
+ read_targets--;
md_sync_acct(bio->bi_bdev, nr_sectors);
generic_make_request(bio);
}
goto abort;
}
err = -ENOMEM;
- conf->thread = md_register_thread(raid1d, mddev, NULL);
+ conf->thread = md_register_thread(raid1d, mddev, "raid1");
if (!conf->thread) {
printk(KERN_ERR
"md/raid1:%s: couldn't allocate thread\n",
const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
unsigned long flags;
struct md_rdev *blocked_rdev;
- int plugged;
int sectors_handled;
int max_sectors;
int sectors;
* of r10_bios is recored in bio->bi_phys_segments just as with
* the read case.
*/
- plugged = mddev_check_plugged(mddev);
r10_bio->read_slot = -1; /* make sure repl_bio gets freed */
raid10_find_phys(conf, r10_bio);
bio_list_add(&conf->pending_bio_list, mbio);
conf->pending_count++;
spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (!mddev_check_plugged(mddev))
+ md_wakeup_thread(mddev->thread);
if (!r10_bio->devs[i].repl_bio)
continue;
bio_list_add(&conf->pending_bio_list, mbio);
conf->pending_count++;
spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (!mddev_check_plugged(mddev))
+ md_wakeup_thread(mddev->thread);
}
/* Don't remove the bias on 'remaining' (one_write_done) until
/* In case raid10d snuck in to freeze_array */
wake_up(&conf->wait_barrier);
-
- if (do_sync || !mddev->bitmap || !plugged)
- md_wakeup_thread(mddev->thread);
}
static void status(struct seq_file *seq, struct mddev *mddev)
if (r10_sync_page_io(rdev,
r10_bio->devs[sl].addr +
sect,
- s<<9, conf->tmppage, WRITE)
+ s, conf->tmppage, WRITE)
== 0) {
/* Well, this device is dead */
printk(KERN_NOTICE
switch (r10_sync_page_io(rdev,
r10_bio->devs[sl].addr +
sect,
- s<<9, conf->tmppage,
+ s, conf->tmppage,
READ)) {
case 0:
/* Well, this device is dead */
slot = r10_bio->read_slot;
printk_ratelimited(
KERN_ERR
- "md/raid10:%s: %s: redirecting"
+ "md/raid10:%s: %s: redirecting "
"sector %llu to another mirror\n",
mdname(mddev),
bdevname(rdev->bdev, b),
blk_start_plug(&plug);
for (;;) {
- flush_pending_writes(conf);
+ if (atomic_read(&mddev->plug_cnt) == 0)
+ flush_pending_writes(conf);
spin_lock_irqsave(&conf->device_lock, flags);
if (list_empty(head)) {
/* want to reconstruct this device */
rb2 = r10_bio;
sect = raid10_find_virt(conf, sector_nr, i);
+ if (sect >= mddev->resync_max_sectors) {
+ /* last stripe is not complete - don't
+ * try to recover this sector.
+ */
+ continue;
+ }
/* Unless we are doing a full sync, or a replacement
* we only need to recover the block if it is set in
* the bitmap
spin_lock_init(&conf->resync_lock);
init_waitqueue_head(&conf->wait_barrier);
- conf->thread = md_register_thread(raid10d, mddev, NULL);
+ conf->thread = md_register_thread(raid10d, mddev, "raid10");
if (!conf->thread)
goto out;
BUG_ON(!list_empty(&sh->lru));
BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
- if (test_bit(STRIPE_DELAYED, &sh->state))
+ if (test_bit(STRIPE_DELAYED, &sh->state) &&
+ !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
list_add_tail(&sh->lru, &conf->delayed_list);
else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
sh->bm_seq - conf->seq_write > 0)
list_add_tail(&sh->lru, &conf->bitmap_list);
else {
+ clear_bit(STRIPE_DELAYED, &sh->state);
clear_bit(STRIPE_BIT_DELAY, &sh->state);
list_add_tail(&sh->lru, &conf->handle_list);
}
* a chance*/
md_check_recovery(conf->mddev);
}
+ /*
+ * Because md_wait_for_blocked_rdev
+ * will dec nr_pending, we must
+ * increment it first.
+ */
+ atomic_inc(&rdev->nr_pending);
md_wait_for_blocked_rdev(rdev, conf->mddev);
} else {
/* Acknowledged bad block - skip the write */
} else {
const char *bdn = bdevname(rdev->bdev, b);
int retry = 0;
+ int set_bad = 0;
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
atomic_inc(&rdev->read_errors);
mdname(conf->mddev),
(unsigned long long)s,
bdn);
- else if (conf->mddev->degraded >= conf->max_degraded)
+ else if (conf->mddev->degraded >= conf->max_degraded) {
+ set_bad = 1;
printk_ratelimited(
KERN_WARNING
"md/raid:%s: read error not correctable "
mdname(conf->mddev),
(unsigned long long)s,
bdn);
- else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
+ } else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) {
/* Oh, no!!! */
+ set_bad = 1;
printk_ratelimited(
KERN_WARNING
"md/raid:%s: read error NOT corrected!! "
mdname(conf->mddev),
(unsigned long long)s,
bdn);
- else if (atomic_read(&rdev->read_errors)
+ } else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
printk(KERN_WARNING
"md/raid:%s: Too many read errors, failing device %s.\n",
else {
clear_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReWrite, &sh->dev[i].flags);
- md_error(conf->mddev, rdev);
+ if (!(set_bad
+ && test_bit(In_sync, &rdev->flags)
+ && rdev_set_badblocks(
+ rdev, sh->sector, STRIPE_SECTORS, 0)))
+ md_error(conf->mddev, rdev);
}
}
rdev_dec_pending(rdev, conf->mddev);
finish:
/* wait for this device to become unblocked */
- if (conf->mddev->external && unlikely(s.blocked_rdev))
- md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
+ if (unlikely(s.blocked_rdev)) {
+ if (conf->mddev->external)
+ md_wait_for_blocked_rdev(s.blocked_rdev,
+ conf->mddev);
+ else
+ /* Internal metadata will immediately
+ * be written by raid5d, so we don't
+ * need to wait here.
+ */
+ rdev_dec_pending(s.blocked_rdev,
+ conf->mddev);
+ }
if (s.handle_bad_blocks)
for (i = disks; i--; ) {
raid_bio->bi_next = (void*)rdev;
align_bi->bi_bdev = rdev->bdev;
align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
- /* No reshape active, so we can trust rdev->data_offset */
- align_bi->bi_sector += rdev->data_offset;
if (!bio_fits_rdev(align_bi) ||
is_badblock(rdev, align_bi->bi_sector, align_bi->bi_size>>9,
return 0;
}
+ /* No reshape active, so we can trust rdev->data_offset */
+ align_bi->bi_sector += rdev->data_offset;
+
spin_lock_irq(&conf->device_lock);
wait_event_lock_irq(conf->wait_for_stripe,
conf->quiesce == 0,
struct stripe_head *sh;
const int rw = bio_data_dir(bi);
int remaining;
- int plugged;
if (unlikely(bi->bi_rw & REQ_FLUSH)) {
md_flush_request(mddev, bi);
bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
- plugged = mddev_check_plugged(mddev);
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
int previous;
if ((bi->bi_rw & REQ_SYNC) &&
!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
atomic_inc(&conf->preread_active_stripes);
+ mddev_check_plugged(mddev);
release_stripe(sh);
} else {
/* cannot get stripe for read-ahead, just give-up */
finish_wait(&conf->wait_for_overlap, &w);
break;
}
-
}
- if (!plugged)
- md_wakeup_thread(mddev->thread);
spin_lock_irq(&conf->device_lock);
remaining = raid5_dec_bi_phys_segments(bi);
int raid_disk, memory, max_disks;
struct md_rdev *rdev;
struct disk_info *disk;
+ char pers_name[6];
if (mddev->new_level != 5
&& mddev->new_level != 4
printk(KERN_INFO "md/raid:%s: allocated %dkB\n",
mdname(mddev), memory);
- conf->thread = md_register_thread(raid5d, mddev, NULL);
+ sprintf(pers_name, "raid%d", mddev->new_level);
+ conf->thread = md_register_thread(raid5d, mddev, pers_name);
if (!conf->thread) {
printk(KERN_ERR
"md/raid:%s: couldn't allocate thread.\n",
if (rdev->saved_raid_disk >= 0 &&
rdev->saved_raid_disk >= first &&
conf->disks[rdev->saved_raid_disk].rdev == NULL)
- disk = rdev->saved_raid_disk;
- else
- disk = first;
- for ( ; disk <= last ; disk++) {
+ first = rdev->saved_raid_disk;
+
+ for (disk = first; disk <= last; disk++) {
p = conf->disks + disk;
if (p->rdev == NULL) {
clear_bit(In_sync, &rdev->flags);
if (rdev->saved_raid_disk != disk)
conf->fullsync = 1;
rcu_assign_pointer(p->rdev, rdev);
- break;
+ goto out;
}
+ }
+ for (disk = first; disk <= last; disk++) {
+ p = conf->disks + disk;
if (test_bit(WantReplacement, &p->rdev->flags) &&
p->replacement == NULL) {
clear_bit(In_sync, &rdev->flags);
break;
}
}
+out:
print_raid5_conf(conf);
return err;
}
if (minor == MAX_DVB_MINORS) {
kfree(dvbdevfops);
kfree(dvbdev);
+ up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
static bool txandrx; /* default = 0 */
module_param(txandrx, bool, 0444);
-MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
+MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX");
static unsigned int wake_sc = 0x800F040C;
module_param(wake_sc, uint, 0644);
data->dev->tx_ir = wbcir_tx;
data->dev->priv = data;
data->dev->dev.parent = &device->dev;
+ data->dev->timeout = MS_TO_NS(100);
+ data->dev->allowed_protos = RC_TYPE_ALL;
if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
urb->context = dev;
urb->pipe = usb_rcvisocpipe(dev->udev,
dev->adev.end_point_addr);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
urb->complete = cx231xx_audio_isocirq;
urb->context = dev;
urb->pipe = usb_rcvbulkpipe(dev->udev,
dev->adev.end_point_addr);
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_flags = 0;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->complete = cx231xx_audio_bulkirq;
urb->transfer_buffer_length = sb_size;
return -ENOMEM;
}
dev->vbi_mode.bulk_ctl.urb[i] = urb;
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_flags = 0;
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
},
[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
.name = "Hauppauge WinTV-HVR1250",
+ .porta = CX23885_ANALOG_VIDEO,
.portc = CX23885_MPEG_DVB,
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .tuner_bus = 1,
+#endif
+ .force_bff = 1,
.input = {{
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
.type = CX23885_VMUX_TELEVISION,
- .vmux = 0,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1,
+ .amux = CX25840_AUDIO8,
.gpio0 = 0xff00,
}, {
- .type = CX23885_VMUX_DEBUG,
- .vmux = 0,
- .gpio0 = 0xff01,
- }, {
+#endif
.type = CX23885_VMUX_COMPOSITE1,
- .vmux = 1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
.gpio0 = 0xff02,
}, {
.type = CX23885_VMUX_SVIDEO,
- .vmux = 2,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
.gpio0 = 0xff02,
} },
},
},
[CX23885_BOARD_HAUPPAUGE_HVR1255] = {
.name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1 |
+ CX25840_DIF_ON,
+ .amux = CX25840_AUDIO8,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1255_22111] = {
+ .name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
.portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x42, /* 0x84 >> 1 */
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1 |
+ CX25840_DIF_ON,
+ .amux = CX25840_AUDIO8,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
},
[CX23885_BOARD_HAUPPAUGE_HVR1210] = {
.name = "Hauppauge WinTV-HVR1210",
}, {
.subvendor = 0x0070,
.subdevice = 0x2259,
- .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255_22111,
}, {
.subvendor = 0x0070,
.subdevice = 0x2291,
struct cx23885_dev *dev = port->dev;
u32 bitmask = 0;
- if (command == XC2028_RESET_CLK)
+ if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH))
return 0;
if (command != 0) {
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
/* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
/* GPIO-6 I2C Gate which can isolate the demod from the bus */
case CX23885_BOARD_HAUPPAUGE_HVR1400:
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
/* FIXME: Implement me */
break;
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1275:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1210:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
*/
switch (dev->board) {
case CX23885_BOARD_TEVII_S470:
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
/* Currently only enabled for the integrated IR controller */
if (!enable_885_ir)
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_MYGICA_X8506:
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
i2c_bus = &dev->i2c_bus[0];
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&hcw_s5h1411_config,
0x60, &dev->i2c_bus[1].i2c_adap,
&hauppauge_tda18271_config);
}
+
+ tda18271_attach(&dev->ts1.analog_fe,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_tda18271_config);
+
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800:
i2c_bus = &dev->i2c_bus[0];
if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
(dev->board == CX23885_BOARD_MPX885) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) {
/* Configure audio routing */
v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
fe = vfe->dvb.frontend;
- if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)
+ if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111))
fe = &dev->ts1.analog_fe;
if (fe && fe->ops.tuner_ops.set_analog_params) {
int ret;
switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
ret = cx23885_set_freq_via_ops(dev, f);
break;
#define CX23885_BOARD_MYGICA_X8507 33
#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
#define CX23885_BOARD_TEVII_S471 35
+#define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
/* ----------------------------------------------------------------------- */
-static void cx23885_std_setup(struct i2c_client *client);
+static void cx23888_std_setup(struct i2c_client *client);
int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
{
finish_wait(&state->fw_wait, &wait);
destroy_workqueue(q);
- /* Call the cx23885 specific std setup func, we no longer rely on
+ /* Call the cx23888 specific std setup func, we no longer rely on
* the generic cx24840 func.
*/
- cx23885_std_setup(client);
+ if (is_cx23888(state))
+ cx23888_std_setup(client);
+ else
+ cx25840_std_setup(client);
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
cx25840_write4(client, 0x410, 0xffff0dbf);
cx25840_write4(client, 0x414, 0x00137d03);
- cx25840_write4(client, 0x418, 0x01008080);
+
+ /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is
+ CHROMA_CTRL */
+ if (is_cx23888(state))
+ cx25840_write4(client, 0x418, 0x01008080);
+ else
+ cx25840_write4(client, 0x418, 0x01000000);
+
cx25840_write4(client, 0x41c, 0x00000000);
- cx25840_write4(client, 0x420, 0x001c3e0f);
+
+ /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is
+ CRUSH_CTRL */
+ if (is_cx23888(state))
+ cx25840_write4(client, 0x420, 0x001c3e0f);
+ else
+ cx25840_write4(client, 0x420, 0x001c8282);
+
cx25840_write4(client, 0x42c, 0x42600000);
cx25840_write4(client, 0x430, 0x0000039b);
cx25840_write4(client, 0x438, 0x00000000);
cx25840_write4(client, 0x8d0, 0x1f063870);
}
- if (is_cx2388x(state)) {
+ if (is_cx23888(state)) {
/* HVR1850 */
/* AUD_IO_CTRL - I2S Input, Parallel1*/
/* - Channel 1 src - Parallel1 (Merlin out) */
}
cx25840_and_or(client, 0x400, ~0xf, fmt);
cx25840_and_or(client, 0x403, ~0x3, pal_m);
- if (is_cx2388x(state))
- cx23885_std_setup(client);
+ if (is_cx23888(state))
+ cx23888_std_setup(client);
else
cx25840_std_setup(client);
if (!is_cx2583x(state))
static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
+ struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
break;
case V4L2_CID_SATURATION:
- cx25840_write(client, 0x420, ctrl->val << 1);
- cx25840_write(client, 0x421, ctrl->val << 1);
+ if (is_cx23888(state)) {
+ cx25840_write(client, 0x418, ctrl->val << 1);
+ cx25840_write(client, 0x419, ctrl->val << 1);
+ } else {
+ cx25840_write(client, 0x420, ctrl->val << 1);
+ cx25840_write(client, 0x421, ctrl->val << 1);
+ }
break;
case V4L2_CID_HUE:
- cx25840_write(client, 0x422, ctrl->val);
+ if (is_cx23888(state))
+ cx25840_write(client, 0x41a, ctrl->val);
+ else
+ cx25840_write(client, 0x422, ctrl->val);
break;
default:
fmt->field = V4L2_FIELD_INTERLACED;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
- Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+ if (is_cx23888(state)) {
+ Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
+ } else {
+ Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+ }
- Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
- Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+ if (is_cx23888(state)) {
+ Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
+ } else {
+ Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+ }
Vlines = fmt->height + (is_50Hz ? 4 : 7);
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (is_cx2388x(state))
- cx23885_std_setup(client);
+ if (is_cx23888(state))
+ cx23888_std_setup(client);
return set_input(client, input, state->aud_input);
}
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (is_cx2388x(state))
- cx23885_std_setup(client);
+ if (is_cx23888(state))
+ cx23888_std_setup(client);
return set_input(client, state->vid_input, input);
}
}
}
-static void cx23885_std_setup(struct i2c_client *client)
+static void cx23888_std_setup(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
v4l2_std_id std = state->std;
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if (dev->board.has_ir_i2c && !disable_ir)
+ if (dev->board.ir_codes && !disable_ir)
request_module("em28xx-rc");
}
set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
v4l2_ctrl_g_ctrl(sd->red));
- set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
- set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
- set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
- v4l2_ctrl_g_ctrl(sd->vflip));
+ if (sd->gain)
+ set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
+ if (sd->exposure)
+ set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
+ if (sd->hflip)
+ set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
+ v4l2_ctrl_g_ctrl(sd->vflip));
reg_w1(gspca_dev, 0x1007, 0x20);
reg_w1(gspca_dev, 0x1061, 0x03);
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- if (!v4l2_ctrl_g_ctrl(sd->autogain))
+ if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
return;
avg_lum = atomic_read(&sd->avg_lum);
#define CSICR1_INV_DATA (1 << 3)
#define CSICR1_INV_PCLK (1 << 2)
#define CSICR1_REDGE (1 << 1)
+#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN)
#define SHIFT_STATFF_LEVEL 22
#define SHIFT_RXFF_LEVEL 19
u32 src_pixel;
u32 ch1_pixel;
u32 irq_flags;
+ u32 csicr1;
};
/* prp resizing parameters */
.ch1_pixel = 0x2ca00565, /* RGB565 */
.irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+ .csicr1 = 0,
}
},
{
.irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
PRP_INTR_CH2FC | PRP_INTR_LBOVF |
PRP_INTR_CH2OVF,
+ .csicr1 = CSICR1_PACK_DIR,
+ }
+ },
+ {
+ .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8,
+ .out_fmt = V4L2_PIX_FMT_YUV420,
+ .cfg = {
+ .channel = 2,
+ .in_fmt = PRP_CNTL_DATA_IN_YUV422,
+ .out_fmt = PRP_CNTL_CH2_OUT_YUV420,
+ .src_pixel = 0x22000888, /* YUV422 (YUYV) */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+ PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+ PRP_INTR_CH2OVF,
+ .csicr1 = CSICR1_SWAP16_EN,
}
},
};
return ret;
}
+ csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1;
+
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_HSYNC_POL;
- if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
- csicr1 |= CSICR1_SWAP16_EN;
if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
csicr1 |= CSICR1_EXT_VSYNC;
if (pcdev->platform_flags & MX2_CAMERA_CCIR)
csicr1 |= CSICR1_GCLK_MODE;
if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
csicr1 |= CSICR1_INV_DATA;
- if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
- csicr1 |= CSICR1_PACK_DIR;
pcdev->csicr1 = csicr1;
return 0;
}
- if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+ if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ code == V4L2_MBUS_FMT_UYVY8_2X8) {
formats++;
if (xlate) {
/*
preview_config_contrast,
NULL,
offsetof(struct prev_params, contrast),
- 0, true,
+ 0, 0, true,
}, /* OMAP3ISP_PREV_BRIGHTNESS */ {
preview_config_brightness,
NULL,
offsetof(struct prev_params, brightness),
- 0, true,
+ 0, 0, true,
},
};
unsigned int elv = prev->crop.top + prev->crop.height - 1;
u32 features;
- if (format->code == V4L2_MBUS_FMT_Y10_1X10) {
+ if (format->code != V4L2_MBUS_FMT_Y10_1X10) {
sph -= 2;
eph += 2;
slv -= 2;
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/mutex.h>
if (pixm)
sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
else
- sizes[i] = size;
+ sizes[i] = max_t(u32, size, frame->payload[i]);
+
allocators[i] = ctx->fimc_dev->alloc_ctx;
}
static int fimc_capture_open(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
- int ret = v4l2_fh_open(file);
-
- if (ret)
- return ret;
+ int ret;
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
- /* Return if the corresponding video mem2mem node is already opened. */
if (fimc_m2m_active(fimc))
return -EBUSY;
set_bit(ST_CAPT_BUSY, &fimc->state);
- pm_runtime_get_sync(&fimc->pdev->dev);
+ ret = pm_runtime_get_sync(&fimc->pdev->dev);
+ if (ret < 0)
+ return ret;
- if (++fimc->vid_cap.refcnt == 1) {
- ret = fimc_pipeline_initialize(&fimc->pipeline,
- &fimc->vid_cap.vfd->entity, true);
- if (ret < 0) {
- dev_err(&fimc->pdev->dev,
- "Video pipeline initialization failed\n");
- pm_runtime_put_sync(&fimc->pdev->dev);
- fimc->vid_cap.refcnt--;
- v4l2_fh_release(file);
- clear_bit(ST_CAPT_BUSY, &fimc->state);
- return ret;
- }
- ret = fimc_capture_ctrls_create(fimc);
+ ret = v4l2_fh_open(file);
+ if (ret)
+ return ret;
- if (!ret && !fimc->vid_cap.user_subdev_api)
- ret = fimc_capture_set_default_format(fimc);
+ if (++fimc->vid_cap.refcnt != 1)
+ return 0;
+
+ ret = fimc_pipeline_initialize(&fimc->pipeline,
+ &fimc->vid_cap.vfd->entity, true);
+ if (ret < 0) {
+ clear_bit(ST_CAPT_BUSY, &fimc->state);
+ pm_runtime_put_sync(&fimc->pdev->dev);
+ fimc->vid_cap.refcnt--;
+ v4l2_fh_release(file);
+ return ret;
}
+ ret = fimc_capture_ctrls_create(fimc);
+
+ if (!ret && !fimc->vid_cap.user_subdev_api)
+ ret = fimc_capture_set_default_format(fimc);
+
return ret;
}
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return -EINVAL;
-
return fimc_fill_format(&ctx->d_frame, f);
}
struct v4l2_mbus_framefmt mf;
struct fimc_fmt *ffmt = NULL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return -EINVAL;
-
if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
struct fimc_fmt *s_fmt = NULL;
int ret, i;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return -EINVAL;
if (vb2_is_busy(&fimc->vid_cap.vbq))
return -EBUSY;
pix->width = mf->width;
pix->height = mf->height;
}
+
fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
for (i = 0; i < ff->fmt->colplanes; i++)
- ff->payload[i] =
- (pix->width * pix->height * ff->fmt->depth[i]) / 8;
+ ff->payload[i] = pix->plane_fmt[i].sizeimage;
set_frame_bounds(ff, pix->width, pix->height);
/* Reset the composition rectangle if not yet configured */
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_pipeline *p = &fimc->pipeline;
+ struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
int ret;
if (fimc_capture_active(fimc))
return -EBUSY;
- media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
- p->m_pipeline);
+ ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline);
+ if (ret < 0)
+ return ret;
if (fimc->vid_cap.user_subdev_api) {
ret = fimc_pipeline_validate(fimc);
- if (ret)
+ if (ret < 0) {
+ media_entity_pipeline_stop(&sd->entity);
return ret;
+ }
}
return vb2_streamon(&fimc->vid_cap.vbq, type);
}
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420M,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 2, 2 },
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
+ .name = "YUV 4:2:0 non-contig. 2p, tiled",
.fourcc = V4L2_PIX_FMT_NV12MT,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
if (!ctrls->ready)
return;
- mutex_lock(&ctrls->handler.lock);
+ mutex_lock(ctrls->handler.lock);
v4l2_ctrl_activate(ctrls->rotate, active);
v4l2_ctrl_activate(ctrls->hflip, active);
v4l2_ctrl_activate(ctrls->vflip, active);
ctx->hflip = 0;
ctx->vflip = 0;
}
- mutex_unlock(&ctrls->handler.lock);
+ mutex_unlock(ctrls->handler.lock);
}
/* Update maximum value of the alpha color control */
pix->width = width;
for (i = 0; i < pix->num_planes; ++i) {
- u32 bpl = pix->plane_fmt[i].bytesperline;
- u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
+ struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
+ u32 bpl = plane_fmt->bytesperline;
if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
bpl = pix->width; /* Planar */
if (i == 0) /* Same bytesperline for each plane. */
bytesperline = bpl;
- pix->plane_fmt[i].bytesperline = bytesperline;
- *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
+ plane_fmt->bytesperline = bytesperline;
+ plane_fmt->sizeimage = max((pix->width * pix->height *
+ fmt->depth[i]) / 8, plane_fmt->sizeimage);
}
}
static int fimc_lite_open(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
- int ret = v4l2_fh_open(file);
+ int ret;
- if (ret)
- return ret;
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
set_bit(ST_FLITE_IN_USE, &fimc->state);
- pm_runtime_get_sync(&fimc->pdev->dev);
+ ret = pm_runtime_get_sync(&fimc->pdev->dev);
+ if (ret < 0)
+ goto done;
- if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA)
- return ret;
+ ret = v4l2_fh_open(file);
+ if (ret < 0)
+ goto done;
- ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity,
- true);
- if (ret < 0) {
- v4l2_err(fimc->vfd, "Video pipeline initialization failed\n");
- pm_runtime_put_sync(&fimc->pdev->dev);
- fimc->ref_count--;
- v4l2_fh_release(file);
- clear_bit(ST_FLITE_IN_USE, &fimc->state);
- }
+ if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) {
+ ret = fimc_pipeline_initialize(&fimc->pipeline,
+ &fimc->vfd->entity, true);
+ if (ret < 0) {
+ pm_runtime_put_sync(&fimc->pdev->dev);
+ fimc->ref_count--;
+ v4l2_fh_release(file);
+ clear_bit(ST_FLITE_IN_USE, &fimc->state);
+ }
- fimc_lite_clear_event_counters(fimc);
+ fimc_lite_clear_event_counters(fimc);
+ }
+done:
+ mutex_unlock(&fimc->lock);
return ret;
}
static int fimc_lite_close(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
clear_bit(ST_FLITE_IN_USE, &fimc->state);
if (fimc->ref_count == 0)
vb2_queue_release(&fimc->vb_queue);
- return v4l2_fh_release(file);
+ ret = v4l2_fh_release(file);
+
+ mutex_unlock(&fimc->lock);
+ return ret;
}
static unsigned int fimc_lite_poll(struct file *file,
struct poll_table_struct *wait)
{
struct fimc_lite *fimc = video_drvdata(file);
- return vb2_poll(&fimc->vb_queue, file, wait);
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return POLL_ERR;
+
+ ret = vb2_poll(&fimc->vb_queue, file, wait);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
}
static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
{
struct fimc_lite *fimc = video_drvdata(file);
- return vb2_mmap(&fimc->vb_queue, vma);
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = vb2_mmap(&fimc->vb_queue, vma);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
}
static const struct v4l2_file_operations fimc_lite_fops = {
if (fimc_lite_active(fimc))
return -EBUSY;
- media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+ ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+ if (ret < 0)
+ return ret;
ret = fimc_pipeline_validate(fimc);
if (ret) {
return 0;
ret = fimc_lite_stop_capture(fimc, suspend);
- if (ret)
+ if (ret < 0 || !fimc_lite_active(fimc))
return ret;
return fimc_pipeline_shutdown(&fimc->pipeline);
int fimc_pipeline_shutdown(struct fimc_pipeline *p)
{
- struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity;
+ struct media_entity *me;
int ret;
+ if (!p || !p->subdevs[IDX_SENSOR])
+ return -EINVAL;
+
+ me = &p->subdevs[IDX_SENSOR]->entity;
mutex_lock(&me->parent->graph_mutex);
ret = __fimc_pipeline_shutdown(p);
mutex_unlock(&me->parent->graph_mutex);
* @source: the source entity to create links to all fimc entities from
* @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
* @pad: the source entity pad index
- * @fimc_id: index of the fimc device for which link should be enabled
+ * @link_mask: bitmask of the fimc devices for which link should be enabled
*/
static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
struct media_entity *source,
struct v4l2_subdev *sensor,
- int pad, int fimc_id)
+ int pad, int link_mask)
{
struct fimc_sensor_info *s_info;
struct media_entity *sink;
if (!fmd->fimc[i]->variant->has_cam_if)
continue;
- flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+ flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
ret = media_entity_create_link(source, pad, sink,
if (!fmd->fimc_lite[i])
continue;
- flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+ if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
+ flags = MEDIA_LNK_FL_ENABLED;
+ else
+ flags = 0;
sink = &fmd->fimc_lite[i]->subdev.entity;
ret = media_entity_create_link(source, pad, sink,
struct s5p_fimc_isp_info *pdata;
struct fimc_sensor_info *s_info;
struct media_entity *source, *sink;
- int i, pad, fimc_id = 0;
- int ret = 0;
- u32 flags;
+ int i, pad, fimc_id = 0, ret = 0;
+ u32 flags, link_mask = 0;
for (i = 0; i < fmd->num_sensors; i++) {
if (fmd->sensor[i].subdev == NULL)
if (source == NULL)
continue;
+ link_mask = 1 << fimc_id++;
ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
- pad, fimc_id++);
+ pad, link_mask);
}
- fimc_id = 0;
for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
if (fmd->csis[i].sd == NULL)
continue;
source = &fmd->csis[i].sd->entity;
pad = CSIS_PAD_SOURCE;
+ link_mask = 1 << fimc_id++;
ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
- pad, fimc_id++);
+ pad, link_mask);
}
/* Create immutable links between each FIMC's subdev and video node */
}
static int __fimc_md_set_camclk(struct fimc_md *fmd,
- struct fimc_sensor_info *s_info,
- bool on)
+ struct fimc_sensor_info *s_info,
+ bool on)
{
struct s5p_fimc_isp_info *pdata = s_info->pdata;
struct fimc_camclk_info *camclk;
if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
return -EINVAL;
- if (s_info->clk_on == on)
- return 0;
camclk = &fmd->camclk[pdata->clk_id];
- dbg("camclk %d, f: %lu, clk: %p, on: %d",
- pdata->clk_id, pdata->clk_frequency, camclk, on);
+ dbg("camclk %d, f: %lu, use_count: %d, on: %d",
+ pdata->clk_id, pdata->clk_frequency, camclk->use_count, on);
if (on) {
if (camclk->use_count > 0 &&
clk_set_rate(camclk->clock, pdata->clk_frequency);
camclk->frequency = pdata->clk_frequency;
ret = clk_enable(camclk->clock);
+ dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
+ clk_get_rate(camclk->clock));
}
- s_info->clk_on = 1;
- dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
- clk_get_rate(camclk->clock));
-
return ret;
}
if (--camclk->use_count == 0) {
clk_disable(camclk->clock);
- s_info->clk_on = 0;
dbg("Disabled camclk %d", pdata->clk_id);
}
return ret;
* devices to which sensors can be attached, either directly or through
* the MIPI CSI receiver. The clock is allowed here to be used by
* multiple sensors concurrently if they use same frequency.
- * The per sensor subdev clk_on attribute helps to synchronize accesses
- * to the sclk_cam clocks from the video and media device nodes.
* This function should only be called when the graph mutex is held.
*/
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
* @pdata: sensor's atrributes passed as media device's platform data
* @subdev: image sensor v4l2 subdev
* @host: fimc device the sensor is currently linked to
- * @clk_on: sclk_cam clock's state associated with this subdev
*
* This data structure applies to image sensor and the writeback subdevs.
*/
struct s5p_fimc_isp_info *pdata;
struct v4l2_subdev *subdev;
struct fimc_dev *host;
- bool clk_on;
};
/**
for (i = 0; i < NUM_CTRLS; i++) {
if (IS_MFC51_PRIV(controls[i].id)) {
+ memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
cfg.ops = &s5p_mfc_dec_ctrl_ops;
cfg.id = controls[i].id;
cfg.min = controls[i].minimum;
}
for (i = 0; i < NUM_CTRLS; i++) {
if (IS_MFC51_PRIV(controls[i].id)) {
+ memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
cfg.ops = &s5p_mfc_enc_ctrl_ops;
cfg.id = controls[i].id;
cfg.min = controls[i].minimum;
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
+ select IRQ_DOMAIN
default n
help
Say yes here if you want support for Texas Instruments TWL6040 audio
+++ /dev/null
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Shared definitions and data structures for the AB5500 MFD driver
- */
-
-/* Read/write operation values. */
-#define AB5500_PERM_RD (0x01)
-#define AB5500_PERM_WR (0x02)
-
-/* Read/write permissions. */
-#define AB5500_PERM_RO (AB5500_PERM_RD)
-#define AB5500_PERM_RW (AB5500_PERM_RD | AB5500_PERM_WR)
-
-#define AB5500_MASK_BASE (0x60)
-#define AB5500_MASK_END (0x79)
-#define AB5500_CHIP_ID (0x20)
-
-/**
- * struct ab5500_reg_range
- * @first: the first address of the range
- * @last: the last address of the range
- * @perm: access permissions for the range
- */
-struct ab5500_reg_range {
- u8 first;
- u8 last;
- u8 perm;
-};
-
-/**
- * struct ab5500_i2c_ranges
- * @count: the number of ranges in the list
- * @range: the list of register ranges
- */
-struct ab5500_i2c_ranges {
- u8 nranges;
- u8 bankid;
- const struct ab5500_reg_range *range;
-};
-
-/**
- * struct ab5500_i2c_banks
- * @count: the number of ranges in the list
- * @range: the list of register ranges
- */
-struct ab5500_i2c_banks {
- u8 nbanks;
- const struct ab5500_i2c_ranges *bank;
-};
-
-/**
- * struct ab5500_bank
- * @slave_addr: I2C slave_addr found in AB5500 specification
- * @name: Documentation name of the bank. For reference
- */
-struct ab5500_bank {
- u8 slave_addr;
- const char *name;
-};
-
-static const struct ab5500_bank bankinfo[AB5500_NUM_BANKS] = {
- [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
- AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP, "VIT_IO_I2C_CLK_TST_OTP"},
- [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
- AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST, "VDDDIG_IO_I2C_CLK_TST"},
- [AB5500_BANK_VDENC] = {AB5500_ADDR_VDENC, "VDENC"},
- [AB5500_BANK_SIM_USBSIM] = {AB5500_ADDR_SIM_USBSIM, "SIM_USBSIM"},
- [AB5500_BANK_LED] = {AB5500_ADDR_LED, "LED"},
- [AB5500_BANK_ADC] = {AB5500_ADDR_ADC, "ADC"},
- [AB5500_BANK_RTC] = {AB5500_ADDR_RTC, "RTC"},
- [AB5500_BANK_STARTUP] = {AB5500_ADDR_STARTUP, "STARTUP"},
- [AB5500_BANK_DBI_ECI] = {AB5500_ADDR_DBI_ECI, "DBI-ECI"},
- [AB5500_BANK_CHG] = {AB5500_ADDR_CHG, "CHG"},
- [AB5500_BANK_FG_BATTCOM_ACC] = {
- AB5500_ADDR_FG_BATTCOM_ACC, "FG_BATCOM_ACC"},
- [AB5500_BANK_USB] = {AB5500_ADDR_USB, "USB"},
- [AB5500_BANK_IT] = {AB5500_ADDR_IT, "IT"},
- [AB5500_BANK_VIBRA] = {AB5500_ADDR_VIBRA, "VIBRA"},
- [AB5500_BANK_AUDIO_HEADSETUSB] = {
- AB5500_ADDR_AUDIO_HEADSETUSB, "AUDIO_HEADSETUSB"},
-};
-
-int ab5500_get_register_interruptible_raw(struct ab5500 *ab, u8 bank, u8 reg,
- u8 *value);
-int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank,
- u8 reg, u8 bitmask, u8 bitvalues);
.reg_bits = 7,
.pad_bits = 1,
.val_bits = 24,
+ .write_flag_mask = 0x80,
.max_register = MC13XXX_NUMREGS,
.cache_type = REGCACHE_NONE,
+ .use_single_rw = 1,
+};
+
+static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ unsigned char w[4] = { *((unsigned char *) reg), 0, 0, 0};
+ unsigned char r[4];
+ unsigned char *p = val;
+ struct device *dev = context;
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_transfer t = {
+ .tx_buf = w,
+ .rx_buf = r,
+ .len = 4,
+ };
+
+ struct spi_message m;
+ int ret;
+
+ if (val_size != 3 || reg_size != 1)
+ return -ENOTSUPP;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ ret = spi_sync(spi, &m);
+
+ memcpy(p, &r[1], 3);
+
+ return ret;
+}
+
+static int mc13xxx_spi_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct spi_device *spi = to_spi_device(dev);
+
+ if (count != 4)
+ return -ENOTSUPP;
+
+ return spi_write(spi, data, count);
+}
+
+/*
+ * We cannot use regmap-spi generic bus implementation here.
+ * The MC13783 chip will get corrupted if CS signal is deasserted
+ * and on i.Mx31 SoC (the target SoC for MC13783 PMIC) the SPI controller
+ * has the following errata (DSPhl22960):
+ * "The CSPI negates SS when the FIFO becomes empty with
+ * SSCTL= 0. Software cannot guarantee that the FIFO will not
+ * drain because of higher priority interrupts and the
+ * non-realtime characteristics of the operating system. As a
+ * result, the SS will negate before all of the data has been
+ * transferred to/from the peripheral."
+ * We workaround this by accessing the SPI controller with a
+ * single transfert.
+ */
+
+static struct regmap_bus regmap_mc13xxx_bus = {
+ .write = mc13xxx_spi_write,
+ .read = mc13xxx_spi_read,
};
static int mc13xxx_spi_probe(struct spi_device *spi)
dev_set_drvdata(&spi->dev, mc13xxx);
spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
- spi->bits_per_word = 32;
mc13xxx->dev = &spi->dev;
mutex_init(&mc13xxx->lock);
- mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
+ mc13xxx->regmap = regmap_init(&spi->dev, ®map_mc13xxx_bus, &spi->dev,
+ &mc13xxx_regmap_spi_config);
+
if (IS_ERR(mc13xxx->regmap)) {
ret = PTR_ERR(mc13xxx->regmap);
dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
+#include <linux/gpio.h>
#include <plat/cpu.h>
#include <plat/usb.h>
#include <linux/pm_runtime.h>
dev_dbg(dev, "starting TI HSUSB Controller\n");
pm_runtime_get_sync(dev);
- spin_lock_irqsave(&omap->lock, flags);
+ if (pdata->ehci_data->phy_reset) {
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+ GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+ GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(10);
+ }
+
+ spin_lock_irqsave(&omap->lock, flags);
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
}
spin_unlock_irqrestore(&omap->lock, flags);
+
+ if (pdata->ehci_data->phy_reset) {
+ /* Hold the PHY in RESET for enough time till
+ * PHY is settled and ready
+ */
+ udelay(10);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ gpio_set_value_cansleep
+ (pdata->ehci_data->reset_gpio_port[0], 1);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ gpio_set_value_cansleep
+ (pdata->ehci_data->reset_gpio_port[1], 1);
+ }
+
pm_runtime_put_sync(dev);
}
+static void omap_usbhs_deinit(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+
+ if (pdata->ehci_data->phy_reset) {
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+ }
+}
+
/**
* usbhs_omap_probe - initialize TI-based HCDs
goto end_probe;
err_alloc:
+ omap_usbhs_deinit(&pdev->dev);
iounmap(omap->tll_base);
err_tll:
{
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
+ omap_usbhs_deinit(&pdev->dev);
iounmap(omap->tll_base);
iounmap(omap->uhh_base);
clk_put(omap->init_60m_fclk);
}
}
- ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq,
+ /* Change IRQ into clear on read mode for efficiency */
+ slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
+ addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL);
+ reg = PALMAS_INT_CTRL_INT_CLEAR;
+
+ regmap_write(palmas->regmap[slave], addr, reg);
+
+ ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
&palmas->irq_data);
if (ret < 0)
goto err;
}
+ children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
+ children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
+
ret = mfd_add_devices(palmas->dev, -1,
children, ARRAY_SIZE(palmas_children),
NULL, regmap_irq_chip_get_base(palmas->irq_data));
{ "twl6035", },
{ "twl6037", },
{ "tps65913", },
+ { /* end */ }
};
MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/err.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65217.h>
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+#ifdef CONFIG_OF
+static struct of_regulator_match reg_matches[] = {
+ { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
+ { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
+ { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
+ { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
+ { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
+ { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
+ { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
+};
+
+static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
+{
+ struct device_node *node = client->dev.of_node;
+ struct tps65217_board *pdata;
+ struct device_node *regs;
+ int count = ARRAY_SIZE(reg_matches);
+ int ret, i;
+
+ regs = of_find_node_by_name(node, "regulators");
+ if (!regs)
+ return NULL;
+
+ ret = of_regulator_match(&client->dev, regs, reg_matches, count);
+ of_node_put(regs);
+ if ((ret < 0) || (ret > count))
+ return NULL;
+
+ count = ret;
+ pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ for (i = 0; i < count; i++) {
+ if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+ continue;
+
+ pdata->tps65217_init_data[i] = reg_matches[i].init_data;
+ pdata->of_node[i] = reg_matches[i].of_node;
+ }
+
+ return pdata;
+}
+
+static struct of_device_id tps65217_of_match[] = {
+ { .compatible = "ti,tps65217", },
+ { },
+};
+#else
+static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
+{
+ return NULL;
+}
+#endif
+
static struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
const struct i2c_device_id *ids)
{
struct tps65217 *tps;
+ struct regulator_init_data *reg_data;
struct tps65217_board *pdata = client->dev.platform_data;
int i, ret;
unsigned int version;
+ if (!pdata && client->dev.of_node)
+ pdata = tps65217_parse_dt(client);
+
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
}
pdev->dev.parent = tps->dev;
- platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
- sizeof(pdata->tps65217_init_data[i]));
+ pdev->dev.of_node = pdata->of_node[i];
+ reg_data = pdata->tps65217_init_data[i];
+ platform_device_add_data(pdev, reg_data, sizeof(*reg_data));
tps->regulator_pdev[i] = pdev;
platform_device_add(pdev);
static struct i2c_driver tps65217_driver = {
.driver = {
.name = "tps65217",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps65217_of_match),
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
err = request_threaded_irq(pdev->irq,
NULL,
mei_interrupt_thread_handler,
- 0, mei_driver_name, dev);
+ IRQF_ONESHOT, mei_driver_name, dev);
else
err = request_threaded_irq(pdev->irq,
mei_interrupt_quick_handler,
if (msg->activate_gru_mq_desc_gpa !=
part_uv->activate_gru_mq_desc_gpa) {
- spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+ spin_lock(&part_uv->flags_lock);
part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
- spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+ spin_unlock(&part_uv->flags_lock);
part_uv->activate_gru_mq_desc_gpa =
msg->activate_gru_mq_desc_gpa;
}
goto egpioreq;
ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- cd->label, host);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT, cd->label, host);
if (ret < 0)
goto eirqreq;
card->ext_csd.generic_cmd6_time);
}
- if (err)
- pr_err("%s: power class selection for ext_csd_bus_width %d"
- " failed\n", mmc_hostname(card->host), bus_width);
-
return err;
}
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
if (err)
- goto err;
+ pr_warning("%s: power class selection to bus width %d"
+ " failed\n", mmc_hostname(card->host),
+ 1 << bus_width);
}
/*
err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
ext_csd);
if (err)
- goto err;
+ pr_warning("%s: power class selection to "
+ "bus width %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
ext_csd);
if (err)
- goto err;
+ pr_warning("%s: power class selection to "
+ "bus width %d ddr %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width, ddr);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
static int cafe_device_ready(struct mtd_info *mtd)
{
struct cafe_priv *cafe = mtd->priv;
- int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
+ int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
cafe_writel(cafe, irqs, NAND_IRQ);
*/
memset(chip->oob_poi, ~0, mtd->oobsize);
chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
-
- read_page_swap_end(this, buf, mtd->writesize,
- this->payload_virt, this->payload_phys,
- nfc_geo->payload_size,
- payload_virt, payload_phys);
}
+
+ read_page_swap_end(this, buf, mtd->writesize,
+ this->payload_virt, this->payload_phys,
+ nfc_geo->payload_size,
+ payload_virt, payload_phys);
exit_nfc:
return ret;
}
static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
+static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
+{
+ int i;
+ u32 *t = trg;
+ const __iomem u32 *s = src;
+
+ for (i = 0; i < (size >> 2); i++)
+ *t++ = __raw_readl(s++);
+}
+
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+ int i;
+ u32 __iomem *t = trg;
+ const u32 *s = src;
+
+ for (i = 0; i < (size >> 2); i++)
+ __raw_writel(*s++, t++);
+}
+
static int check_int_v3(struct mxc_nand_host *host)
{
uint32_t tmp;
wait_op_done(host, true);
- memcpy_fromio(host->data_buf, host->main_area0, 16);
+ memcpy32_fromio(host->data_buf, host->main_area0, 16);
}
/* Request the NANDFC to perform a read of the NAND device ID. */
/* Wait for operation to complete */
wait_op_done(host, true);
- memcpy_fromio(host->data_buf, host->main_area0, 16);
+ memcpy32_fromio(host->data_buf, host->main_area0, 16);
if (this->options & NAND_BUSWIDTH_16) {
/* compress the ID info */
if (bfrom) {
for (i = 0; i < n - 1; i++)
- memcpy_fromio(d + i * j, s + i * t, j);
+ memcpy32_fromio(d + i * j, s + i * t, j);
/* the last section */
- memcpy_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
+ memcpy32_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
} else {
for (i = 0; i < n - 1; i++)
- memcpy_toio(&s[i * t], &d[i * j], j);
+ memcpy32_toio(&s[i * t], &d[i * j], j);
/* the last section */
- memcpy_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
+ memcpy32_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
}
}
host->devtype_data->send_page(mtd, NFC_OUTPUT);
- memcpy_fromio(host->data_buf, host->main_area0, mtd->writesize);
+ memcpy32_fromio(host->data_buf, host->main_area0,
+ mtd->writesize);
copy_spare(mtd, true);
break;
break;
case NAND_CMD_PAGEPROG:
- memcpy_toio(host->main_area0, host->data_buf, mtd->writesize);
+ memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
copy_spare(mtd, false);
host->devtype_data->send_page(mtd, NFC_INPUT);
host->devtype_data->send_cmd(host, command, true);
/* propagate ecc info to mtd_info */
mtd->ecclayout = chip->ecc.layout;
mtd->ecc_strength = chip->ecc.strength;
+ /*
+ * Initialize bitflip_threshold to its default prior scan_bbt() call.
+ * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+ * properly set.
+ */
+ if (!mtd->bitflip_threshold)
+ mtd->bitflip_threshold = mtd->ecc_strength;
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
return kstrdup(buf, GFP_KERNEL);
}
-static uint64_t divide(uint64_t n, uint32_t d)
-{
- do_div(n, d);
- return n;
-}
-
/*
* Initialize the nandsim structure.
*
ns->geom.oobsz = mtd->oobsize;
ns->geom.secsz = mtd->erasesize;
ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz;
- ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz);
+ ns->geom.pgnum = div_u64(ns->geom.totsz, ns->geom.pgsz);
ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
ns->geom.secshift = ffs(ns->geom.secsz) - 1;
ns->geom.pgshift = chip->page_shift;
if (!rptwear)
return 0;
- wear_eb_count = divide(mtd->size, mtd->erasesize);
+ wear_eb_count = div_u64(mtd->size, mtd->erasesize);
mem = wear_eb_count * sizeof(unsigned long);
if (mem / sizeof(unsigned long) != wear_eb_count) {
NS_ERR("Too many erase blocks for wear reporting\n");
if (priv->mode == MQ_MG_MODE) {
baddr = ®s->txic0;
for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
- if (likely(priv->tx_queue[i]->txcoalescing)) {
- gfar_write(baddr + i, 0);
+ gfar_write(baddr + i, 0);
+ if (likely(priv->tx_queue[i]->txcoalescing))
gfar_write(baddr + i, priv->tx_queue[i]->txic);
- }
}
baddr = ®s->rxic0;
for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
- if (likely(priv->rx_queue[i]->rxcoalescing)) {
- gfar_write(baddr + i, 0);
+ gfar_write(baddr + i, 0);
+ if (likely(priv->rx_queue[i]->rxcoalescing))
gfar_write(baddr + i, priv->rx_queue[i]->rxic);
- }
}
}
}
#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
* @sk_buff: socket buffer with received data
**/
static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
- __le16 csum, struct sk_buff *skb)
+ struct sk_buff *skb)
{
u16 status = (u16)status_err;
u8 errors = (u8)(status_err >> 24);
if (status & E1000_RXD_STAT_IXSM)
return;
- /* TCP/UDP checksum error bit is set */
- if (errors & E1000_RXD_ERR_TCPE) {
+ /* TCP/UDP checksum error bit or IP checksum error bit is set */
+ if (errors & (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) {
/* let the stack verify checksum errors */
adapter->hw_csum_err++;
return;
return;
/* It must be a TCP or UDP packet with a valid checksum */
- if (status & E1000_RXD_STAT_TCPCS) {
- /* TCP checksum is good */
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- /*
- * IP fragment with UDP payload
- * Hardware complements the payload checksum, so we undo it
- * and then put the value in host order for further stack use.
- */
- __sum16 sum = (__force __sum16)swab16((__force u16)csum);
- skb->csum = csum_unfold(~sum);
- skb->ip_summed = CHECKSUM_COMPLETE;
- }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
adapter->hw_csum_good++;
}
skb_put(skb, length);
/* Receive Checksum Offload */
- e1000_rx_checksum(adapter, staterr,
- rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+ e1000_rx_checksum(adapter, staterr, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
total_rx_bytes += skb->len;
total_rx_packets++;
- e1000_rx_checksum(adapter, staterr,
- rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+ e1000_rx_checksum(adapter, staterr, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
}
}
- /* Receive Checksum Offload XXX recompute due to CRC strip? */
- e1000_rx_checksum(adapter, staterr,
- rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+ /* Receive Checksum Offload */
+ e1000_rx_checksum(adapter, staterr, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
/* Enable Receive Checksum Offload for TCP and UDP */
rxcsum = er32(RXCSUM);
- if (adapter->netdev->features & NETIF_F_RXCSUM) {
+ if (adapter->netdev->features & NETIF_F_RXCSUM)
rxcsum |= E1000_RXCSUM_TUOFL;
-
- /*
- * IPv4 payload checksum for UDP fragments must be
- * used in conjunction with packet-split.
- */
- if (adapter->rx_ps_pages)
- rxcsum |= E1000_RXCSUM_IPPCSE;
- } else {
+ else
rxcsum &= ~E1000_RXCSUM_TUOFL;
- /* no need to clear IPPCSE as it defaults to 0 */
- }
ew32(RXCSUM, rxcsum);
if (adapter->hw.mac.type == e1000_pch2lan) {
int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
/* Jumbo frame support */
- if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
- if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
- e_err("Jumbo Frames not supported.\n");
- return -EINVAL;
- }
-
- /*
- * IP payload checksum (enabled with jumbos/packet-split when
- * Rx checksum is enabled) and generation of RSS hash is
- * mutually exclusive in the hardware.
- */
- if ((netdev->features & NETIF_F_RXCSUM) &&
- (netdev->features & NETIF_F_RXHASH)) {
- e_err("Jumbo frames cannot be enabled when both receive checksum offload and receive hashing are enabled. Disable one of the receive offload features before enabling jumbos.\n");
- return -EINVAL;
- }
+ if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
+ !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+ e_err("Jumbo Frames not supported.\n");
+ return -EINVAL;
}
/* Supported frame sizes */
NETIF_F_RXALL)))
return 0;
- /*
- * IP payload checksum (enabled with jumbos/packet-split when Rx
- * checksum is enabled) and generation of RSS hash is mutually
- * exclusive in the hardware.
- */
- if (adapter->rx_ps_pages &&
- (features & NETIF_F_RXCSUM) && (features & NETIF_F_RXHASH)) {
- e_err("Enabling both receive checksum offload and receive hashing is not possible with jumbo frames. Disable jumbos or enable only one of the receive offload features.\n");
- return -EINVAL;
- }
-
if (changed & NETIF_F_RXFCS) {
if (features & NETIF_F_RXFCS) {
adapter->flags2 &= ~FLAG2_CRC_STRIPPING;
struct igbvf_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- if ((ec->rx_coalesce_usecs > IGBVF_MAX_ITR_USECS) ||
- ((ec->rx_coalesce_usecs > 3) &&
- (ec->rx_coalesce_usecs < IGBVF_MIN_ITR_USECS)) ||
- (ec->rx_coalesce_usecs == 2))
- return -EINVAL;
-
- /* convert to rate of irq's per second */
- if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) {
+ if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) &&
+ (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) {
+ adapter->current_itr = ec->rx_coalesce_usecs << 2;
+ adapter->requested_itr = 1000000000 /
+ (adapter->current_itr * 256);
+ } else if ((ec->rx_coalesce_usecs == 3) ||
+ (ec->rx_coalesce_usecs == 2)) {
adapter->current_itr = IGBVF_START_ITR;
adapter->requested_itr = ec->rx_coalesce_usecs;
- } else {
- adapter->current_itr = ec->rx_coalesce_usecs << 2;
+ } else if (ec->rx_coalesce_usecs == 0) {
+ /*
+ * The user's desire is to turn off interrupt throttling
+ * altogether, but due to HW limitations, we can't do that.
+ * Instead we set a very small value in EITR, which would
+ * allow ~967k interrupts per second, but allow the adapter's
+ * internal clocking to still function properly.
+ */
+ adapter->current_itr = 4;
adapter->requested_itr = 1000000000 /
(adapter->current_itr * 256);
- }
+ } else
+ return -EINVAL;
writel(adapter->current_itr,
hw->hw_addr + adapter->rx_ring->itr_register);
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
{
struct usbnet *dev = usb_get_intfdata(intf);
+
+ /* can be called while disconnecting */
+ if (!dev)
+ return 0;
return qmi_wwan_manage_power(dev, on);
}
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
+ DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX);
enum ath_crypt_caps crypt_caps;
unsigned int clockrate;
if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
- ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+ ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
!ah->is_pciexpress)) {
ah->config.serialize_regmode =
SER_REG_MODE_ON;
__skb_unlink(skb, &rx_edma->rx_fifo);
list_add_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_edma_buf_link(sc, qtype);
- } else {
- bf = NULL;
}
+
+ bf = NULL;
}
*dest = bf;
* descriptor does contain a valid key index. This has been observed
* mostly with CCMP encryption.
*/
- if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID)
+ if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
+ !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
if (!rx_stats->rs_datalen) {
return -EIO;
set_bit(idx, common->keymap);
+ if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
+ set_bit(idx, common->ccmp_keymap);
+
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
set_bit(idx + 64, common->keymap);
set_bit(idx, common->tkip_keymap);
return;
clear_bit(key->hw_key_idx, common->keymap);
+ clear_bit(key->hw_key_idx, common->ccmp_keymap);
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
return;
switch (op) {
case ADD:
ret = iwlagn_mac_sta_add(hw, vif, sta);
+ if (ret)
+ break;
+ /*
+ * Clear the in-progress flag, the AP station entry was added
+ * but we'll initialize LQ only when we've associated (which
+ * would also clear the in-progress flag). This is necessary
+ * in case we never initialize LQ because association fails.
+ */
+ spin_lock_bh(&priv->sta_lock);
+ priv->stations[iwl_sta_id(sta)].used &=
+ ~IWL_STA_UCODE_INPROGRESS;
+ spin_unlock_bh(&priv->sta_lock);
break;
case REMOVE:
ret = iwlagn_mac_sta_remove(hw, vif, sta);
else
last_seq = priv->rx_seq[tid];
- if (last_seq >= new_node->start_win)
+ if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
+ last_seq >= new_node->start_win)
new_node->start_win = last_seq + 1;
new_node->win_size = win_size;
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
- memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
+ mwifiex_reset_11n_rx_seq_num(priv);
}
#define ADDBA_RSP_STATUS_ACCEPT 0
+#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff
+
+static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
+{
+ memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+}
+
int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
u16 seqNum,
u16 tid, u8 *ta,
/* save assoc resp ie index after auto-indexing */
*assoc_idx = *((u16 *)pos);
+ kfree(ap_custom_ie);
return ret;
}
dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
adapter->event_cause = *(u32 *) skb->data;
- skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
-
if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
- memcpy(adapter->event_body, skb->data, skb->len);
+ memcpy(adapter->event_body,
+ skb->data + MWIFIEX_EVENT_HEADER_LEN,
+ skb->len);
/* event cause has been saved to adapter->event_cause */
adapter->event_received = true;
break;
case EVENT_UAP_STA_ASSOC:
- skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
memset(&sinfo, 0, sizeof(sinfo));
- event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
+ event = (struct mwifiex_assoc_event *)
+ (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
len = -1;
GFP_KERNEL);
break;
case EVENT_UAP_STA_DEAUTH:
- skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
- cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
- GFP_KERNEL);
+ cfg80211_del_sta(priv->netdev, adapter->event_body +
+ MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
break;
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
struct device *dev = adapter->dev;
u32 recv_type;
__le32 tmp;
+ int ret;
if (adapter->hs_activated)
mwifiex_process_hs_config(adapter);
case MWIFIEX_USB_TYPE_CMD:
if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
dev_err(dev, "CMD: skb->len too large\n");
- return -1;
+ ret = -1;
+ goto exit_restore_skb;
} else if (!adapter->curr_cmd) {
dev_dbg(dev, "CMD: no curr_cmd\n");
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(
adapter, skb->data,
skb->len);
- return 0;
+ ret = 0;
+ goto exit_restore_skb;
}
- return -1;
+ ret = -1;
+ goto exit_restore_skb;
}
adapter->curr_cmd->resp_skb = skb;
case MWIFIEX_USB_TYPE_EVENT:
if (skb->len < sizeof(u32)) {
dev_err(dev, "EVENT: skb->len too small\n");
- return -1;
+ ret = -1;
+ goto exit_restore_skb;
}
skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
adapter->event_cause = le32_to_cpu(tmp);
- skb_pull(skb, sizeof(u32));
dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
if (skb->len > MAX_EVENT_SIZE) {
dev_err(dev, "EVENT: event body too large\n");
- return -1;
+ ret = -1;
+ goto exit_restore_skb;
}
- skb_copy_from_linear_data(skb, adapter->event_body,
- skb->len);
+ memcpy(adapter->event_body, skb->data +
+ MWIFIEX_EVENT_HEADER_LEN, skb->len);
+
adapter->event_received = true;
adapter->event_skb = skb;
break;
}
return -EINPROGRESS;
+
+exit_restore_skb:
+ /* The buffer will be reused for further cmds/events */
+ skb_push(skb, INTF_HEADER_LEN);
+
+ return ret;
}
static void mwifiex_usb_rx_complete(struct urb *urb)
priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+ mwifiex_reset_11n_rx_seq_num(priv);
+
atomic_set(&priv->wmm.tx_pkts_queued, 0);
atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
}
if (!ptr->is_11n_enabled ||
mwifiex_is_ba_stream_setup(priv, ptr, tid) ||
+ priv->wps.session_enable ||
((priv->sec_info.wpa_enabled ||
priv->sec_info.wpa2_enabled) &&
!priv->wpa_is_gtk_set)) {
{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
{RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
+ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
+ {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
/* HP - Lite-On ,8188CUS Slim Combo */
{RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
{RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
{RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
{RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
{RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
+ {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/
{RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
{RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/
{RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
config WLCORE
tristate "TI wlcore support"
depends on WL_TI && GENERIC_HARDIRQS && MAC80211
- depends on INET
select FW_LOADER
---help---
This module contains the main code for TI WLAN chips. It abstracts
for(; lookup->compatible != NULL; lookup++) {
if (!of_device_is_compatible(np, lookup->compatible))
continue;
- if (of_address_to_resource(np, 0, &res))
- continue;
- if (res.start != lookup->phys_addr)
- continue;
+ if (!of_address_to_resource(np, 0, &res))
+ if (res.start != lookup->phys_addr)
+ continue;
pr_debug("%s: devname=%s\n", np->full_name, lookup->name);
return lookup;
}
of_node_put(root);
return rc;
}
+EXPORT_SYMBOL_GPL(of_platform_populate);
#endif /* CONFIG_OF_ADDRESS */
pci_pm_set_unknown_state(pci_dev);
+ /*
+ * Some BIOSes from ASUS have a bug: If a USB EHCI host controller's
+ * PCI COMMAND register isn't 0, the BIOS assumes that the controller
+ * hasn't been quiesced and tries to turn it off. If the controller
+ * is already in D3, this can hang or cause memory corruption.
+ *
+ * Since the value of the COMMAND register doesn't matter once the
+ * device has been suspended, we can safely set it to 0 here.
+ */
+ if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
+ pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+
return 0;
}
if (target_state == PCI_POWER_ERROR)
return -EIO;
- /* Some devices mustn't be in D3 during system sleep */
- if (target_state == PCI_D3hot &&
- (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP))
- return 0;
-
pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
error = pci_set_power_state(dev, target_state);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
-/*
- * The Intel 6 Series/C200 Series chipset's EHCI controllers on many
- * ASUS motherboards will cause memory corruption or a system crash
- * if they are in D3 while the system is put into S3 sleep.
- */
-static void __devinit asus_ehci_no_d3(struct pci_dev *dev)
-{
- const char *sys_info;
- static const char good_Asus_board[] = "P8Z68-V";
-
- if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)
- return;
- if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK)
- return;
- sys_info = dmi_get_system_info(DMI_BOARD_NAME);
- if (sys_info && memcmp(sys_info, good_Asus_board,
- sizeof(good_Asus_board) - 1) == 0)
- return;
-
- dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n");
- dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP;
- device_set_wakeup_capable(&dev->dev, false);
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
-
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
{
If unsure, say no.
+
if REGULATOR
config REGULATOR_DEBUG
If you have a AnalogicTech AAT2870 say Y to enable the
regulator driver.
+config REGULATOR_ARIZONA
+ tristate "Wolfson Arizona class devices"
+ depends on MFD_ARIZONA
+ help
+ Support for the regulators found on Wolfson Arizona class
+ devices.
+
config REGULATOR_DA903X
tristate "Dialog Semiconductor DA9030/DA9034 regulators"
depends on PMIC_DA903X
via I2C bus. The provided regulator is suitable for S3C6410
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX77686
+ tristate "Maxim 77686 regulator"
+ depends on MFD_MAX77686
+ help
+ This driver controls a Maxim 77686 regulator
+ via I2C bus. The provided regulator is suitable for
+ Exynos-4 chips to control VARM and VINT voltages.
+
config REGULATOR_PCAP
tristate "Motorola PCAP2 regulator driver"
depends on EZX_PCAP
Say Y here to support the voltage regulators and convertors
on National Semiconductors LP3972 PMIC
+config REGULATOR_LP872X
+ bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
+ depends on I2C=y
+ select REGMAP_I2C
+ help
+ This driver supports LP8720/LP8725 PMIC
+
+config REGULATOR_LP8788
+ bool "TI LP8788 Power Regulators"
+ depends on MFD_LP8788
+ help
+ This driver supports LP8788 voltage regulator chip.
+
config REGULATOR_PCF50633
tristate "NXP PCF50633 regulator driver"
depends on MFD_PCF50633
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
+config REGULATOR_S2MPS11
+ tristate "Samsung S2MPS11 voltage regulator"
+ depends on MFD_SEC_CORE
+ help
+ This driver supports a Samsung S2MPS11 voltage output regulator
+ via I2C bus. S2MPS11 is comprised of high efficient Buck converters
+ including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
+
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
depends on MFD_S5M_CORE
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
+obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
+obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
+obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
+obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
struct aat2870_data *aat2870;
struct regulator_desc desc;
- const int *voltages; /* uV */
-
- int min_uV;
- int max_uV;
-
u8 enable_addr;
u8 enable_shift;
u8 enable_mask;
u8 voltage_mask;
};
-static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
-
- return ri->voltages[selector];
-}
-
static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
}
static struct regulator_ops aat2870_ldo_ops = {
- .list_voltage = aat2870_ldo_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage_sel = aat2870_ldo_set_voltage_sel,
.get_voltage_sel = aat2870_ldo_get_voltage_sel,
.enable = aat2870_ldo_enable,
.is_enabled = aat2870_ldo_is_enabled,
};
-static const int aat2870_ldo_voltages[] = {
+static const unsigned int aat2870_ldo_voltages[] = {
1200000, 1300000, 1500000, 1600000,
1800000, 2000000, 2200000, 2500000,
2600000, 2700000, 2800000, 2900000,
.name = #ids, \
.id = AAT2870_ID_##ids, \
.n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \
+ .volt_table = aat2870_ldo_voltages, \
.ops = &aat2870_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
- .voltages = aat2870_ldo_voltages, \
- .min_uV = 1200000, \
- .max_uV = 3300000, \
}
static struct aat2870_regulator aat2870_regulators[] = {
* @dev: handle to the device
* @plfdata: AB3100 platform data passed in at probe time
* @regreg: regulator register number in the AB3100
- * @fixed_voltage: a fixed voltage for this regulator, if this
- * 0 the voltages array is used instead.
- * @typ_voltages: an array of available typical voltages for
- * this regulator
- * @voltages_len: length of the array of available voltages
*/
struct ab3100_regulator {
struct regulator_dev *rdev;
struct device *dev;
struct ab3100_platform_data *plfdata;
u8 regreg;
- int fixed_voltage;
- int const *typ_voltages;
- u8 voltages_len;
};
/* The order in which registers are initialized */
#define LDO_C_VOLTAGE 2650000
#define LDO_D_VOLTAGE 2650000
-static const int ldo_e_buck_typ_voltages[] = {
+static const unsigned int ldo_e_buck_typ_voltages[] = {
1800000,
1400000,
1300000,
900000,
};
-static const int ldo_f_typ_voltages[] = {
+static const unsigned int ldo_f_typ_voltages[] = {
1800000,
1400000,
1300000,
2650000,
};
-static const int ldo_g_typ_voltages[] = {
+static const unsigned int ldo_g_typ_voltages[] = {
2850000,
2750000,
1800000,
1500000,
};
-static const int ldo_h_typ_voltages[] = {
+static const unsigned int ldo_h_typ_voltages[] = {
2750000,
1800000,
1500000,
1200000,
};
-static const int ldo_k_typ_voltages[] = {
+static const unsigned int ldo_k_typ_voltages[] = {
2750000,
1800000,
};
ab3100_regulators[AB3100_NUM_REGULATORS] = {
{
.regreg = AB3100_LDO_A,
- .fixed_voltage = LDO_A_VOLTAGE,
},
{
.regreg = AB3100_LDO_C,
- .fixed_voltage = LDO_C_VOLTAGE,
},
{
.regreg = AB3100_LDO_D,
- .fixed_voltage = LDO_D_VOLTAGE,
},
{
.regreg = AB3100_LDO_E,
- .typ_voltages = ldo_e_buck_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
},
{
.regreg = AB3100_LDO_F,
- .typ_voltages = ldo_f_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_f_typ_voltages),
},
{
.regreg = AB3100_LDO_G,
- .typ_voltages = ldo_g_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_g_typ_voltages),
},
{
.regreg = AB3100_LDO_H,
- .typ_voltages = ldo_h_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_h_typ_voltages),
},
{
.regreg = AB3100_LDO_K,
- .typ_voltages = ldo_k_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_k_typ_voltages),
},
{
.regreg = AB3100_LDO_EXT,
},
{
.regreg = AB3100_BUCK,
- .typ_voltages = ldo_e_buck_typ_voltages,
- .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
},
};
*/
static int ab3100_enable_regulator(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
int err;
u8 regval;
static int ab3100_disable_regulator(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
int err;
u8 regval;
static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
u8 regval;
int err;
return regval & AB3100_REG_ON_MASK;
}
-static int ab3100_list_voltage_regulator(struct regulator_dev *reg,
- unsigned selector)
-{
- struct ab3100_regulator *abreg = reg->reg_data;
-
- if (selector >= abreg->voltages_len)
- return -EINVAL;
- return abreg->typ_voltages[selector];
-}
-
static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
u8 regval;
int err;
- /* Return the voltage for fixed regulators immediately */
- if (abreg->fixed_voltage)
- return abreg->fixed_voltage;
-
/*
* For variable types, read out setting and index into
* supplied voltage list.
regval &= 0xE0;
regval >>= 5;
- if (regval >= abreg->voltages_len) {
+ if (regval >= reg->desc->n_voltages) {
dev_err(®->dev,
"regulator register %02x contains an illegal voltage setting\n",
abreg->regreg);
return -EINVAL;
}
- return abreg->typ_voltages[regval];
+ return reg->desc->volt_table[regval];
}
static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg,
unsigned selector)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
u8 regval;
int err;
static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
int uV)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
u8 regval;
int err;
int bestindex;
*/
static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
+ struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
return abreg->plfdata->external_voltage;
}
-static int ab3100_enable_time_regulator(struct regulator_dev *reg)
+static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg)
{
- struct ab3100_regulator *abreg = reg->reg_data;
-
- /* Per-regulator power on delay from spec */
- switch (abreg->regreg) {
- case AB3100_LDO_A: /* Fallthrough */
- case AB3100_LDO_C: /* Fallthrough */
- case AB3100_LDO_D: /* Fallthrough */
- case AB3100_LDO_E: /* Fallthrough */
- case AB3100_LDO_H: /* Fallthrough */
- case AB3100_LDO_K:
- return 200;
- case AB3100_LDO_F:
- return 600;
- case AB3100_LDO_G:
- return 400;
- case AB3100_BUCK:
- return 1000;
- default:
- break;
- }
- return 0;
+ return reg->desc->min_uV;
}
static struct regulator_ops regulator_ops_fixed = {
+ .list_voltage = regulator_list_voltage_linear,
.enable = ab3100_enable_regulator,
.disable = ab3100_disable_regulator,
.is_enabled = ab3100_is_enabled_regulator,
- .get_voltage = ab3100_get_voltage_regulator,
- .enable_time = ab3100_enable_time_regulator,
+ .get_voltage = ab3100_get_fixed_voltage_regulator,
};
static struct regulator_ops regulator_ops_variable = {
.is_enabled = ab3100_is_enabled_regulator,
.get_voltage = ab3100_get_voltage_regulator,
.set_voltage_sel = ab3100_set_voltage_regulator_sel,
- .list_voltage = ab3100_list_voltage_regulator,
- .enable_time = ab3100_enable_time_regulator,
+ .list_voltage = regulator_list_voltage_table,
};
static struct regulator_ops regulator_ops_variable_sleepable = {
.get_voltage = ab3100_get_voltage_regulator,
.set_voltage_sel = ab3100_set_voltage_regulator_sel,
.set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
- .list_voltage = ab3100_list_voltage_regulator,
- .enable_time = ab3100_enable_time_regulator,
+ .list_voltage = regulator_list_voltage_table,
};
/*
.name = "LDO_A",
.id = AB3100_LDO_A,
.ops = ®ulator_ops_fixed,
+ .n_voltages = 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = LDO_A_VOLTAGE,
+ .enable_time = 200,
},
{
.name = "LDO_C",
.id = AB3100_LDO_C,
.ops = ®ulator_ops_fixed,
+ .n_voltages = 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = LDO_C_VOLTAGE,
+ .enable_time = 200,
},
{
.name = "LDO_D",
.id = AB3100_LDO_D,
.ops = ®ulator_ops_fixed,
+ .n_voltages = 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = LDO_D_VOLTAGE,
+ .enable_time = 200,
},
{
.name = "LDO_E",
.id = AB3100_LDO_E,
.ops = ®ulator_ops_variable_sleepable,
.n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+ .volt_table = ldo_e_buck_typ_voltages,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 200,
},
{
.name = "LDO_F",
.id = AB3100_LDO_F,
.ops = ®ulator_ops_variable,
.n_voltages = ARRAY_SIZE(ldo_f_typ_voltages),
+ .volt_table = ldo_f_typ_voltages,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 600,
},
{
.name = "LDO_G",
.id = AB3100_LDO_G,
.ops = ®ulator_ops_variable,
.n_voltages = ARRAY_SIZE(ldo_g_typ_voltages),
+ .volt_table = ldo_g_typ_voltages,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 400,
},
{
.name = "LDO_H",
.id = AB3100_LDO_H,
.ops = ®ulator_ops_variable,
.n_voltages = ARRAY_SIZE(ldo_h_typ_voltages),
+ .volt_table = ldo_h_typ_voltages,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 200,
},
{
.name = "LDO_K",
.id = AB3100_LDO_K,
.ops = ®ulator_ops_variable,
.n_voltages = ARRAY_SIZE(ldo_k_typ_voltages),
+ .volt_table = ldo_k_typ_voltages,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 200,
},
{
.name = "LDO_EXT",
.n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .enable_time = 1000,
},
};
* @dev: device pointer
* @desc: regulator description
* @regulator_dev: regulator device
- * @max_uV: maximum voltage (for variable voltage supplies)
- * @min_uV: minimum voltage (for variable voltage supplies)
- * @fixed_uV: typical voltage (for fixed voltage supplies)
* @update_bank: bank to control on/off
* @update_reg: register to control on/off
* @update_mask: mask to enable/disable regulator
* @voltage_bank: bank to control regulator voltage
* @voltage_reg: register to control regulator voltage
* @voltage_mask: mask to control regulator voltage
- * @voltages: supported voltage table
- * @voltages_len: number of supported voltages for the regulator
* @delay: startup/set voltage delay in us
*/
struct ab8500_regulator_info {
struct device *dev;
struct regulator_desc desc;
struct regulator_dev *regulator;
- int max_uV;
- int min_uV;
- int fixed_uV;
u8 update_bank;
u8 update_reg;
u8 update_mask;
u8 voltage_bank;
u8 voltage_reg;
u8 voltage_mask;
- int const *voltages;
- int voltages_len;
unsigned int delay;
};
/* voltage tables for the vauxn/vintcore supplies */
-static const int ldo_vauxn_voltages[] = {
+static const unsigned int ldo_vauxn_voltages[] = {
1100000,
1200000,
1300000,
3300000,
};
-static const int ldo_vaux3_voltages[] = {
+static const unsigned int ldo_vaux3_voltages[] = {
1200000,
1500000,
1800000,
2910000,
};
-static const int ldo_vintcore_voltages[] = {
+static const unsigned int ldo_vintcore_voltages[] = {
1200000,
1225000,
1250000,
return false;
}
-static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
- struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
- if (info == NULL) {
- dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
- return -EINVAL;
- }
-
- /* return the uV for the fixed regulators */
- if (info->fixed_uV)
- return info->fixed_uV;
-
- if (selector >= info->voltages_len)
- return -EINVAL;
-
- return info->voltages[selector];
-}
-
static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
int ret, val;
unsigned int new_sel)
{
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
- /* If the regulator isn't on, it won't take time here */
- ret = ab8500_regulator_is_enabled(rdev);
- if (ret < 0)
- return ret;
- if (!ret)
- return 0;
return info->delay;
}
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage_sel = ab8500_regulator_get_voltage_sel,
.set_voltage_sel = ab8500_regulator_set_voltage_sel,
- .list_voltage = ab8500_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.enable_time = ab8500_regulator_enable_time,
.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
};
static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
{
- struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
- if (info == NULL) {
- dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
- return -EINVAL;
- }
-
- return info->fixed_uV;
+ return rdev->desc->min_uV;
}
static struct regulator_ops ab8500_regulator_fixed_ops = {
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage = ab8500_fixed_get_voltage,
- .list_voltage = ab8500_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
.enable_time = ab8500_regulator_enable_time,
- .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
};
static struct ab8500_regulator_info
* Variable Voltage Regulators
* name, min mV, max mV,
* update bank, reg, mask, enable val
- * volt bank, reg, mask, table, table length
+ * volt bank, reg, mask
*/
[AB8500_LDO_AUX1] = {
.desc = {
.id = AB8500_LDO_AUX1,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
},
- .min_uV = 1100000,
- .max_uV = 3300000,
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x03,
.voltage_bank = 0x04,
.voltage_reg = 0x1f,
.voltage_mask = 0x0f,
- .voltages = ldo_vauxn_voltages,
- .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages),
},
[AB8500_LDO_AUX2] = {
.desc = {
.id = AB8500_LDO_AUX2,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
},
- .min_uV = 1100000,
- .max_uV = 3300000,
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x0c,
.voltage_bank = 0x04,
.voltage_reg = 0x20,
.voltage_mask = 0x0f,
- .voltages = ldo_vauxn_voltages,
- .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages),
},
[AB8500_LDO_AUX3] = {
.desc = {
.id = AB8500_LDO_AUX3,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vaux3_voltages),
+ .volt_table = ldo_vaux3_voltages,
},
- .min_uV = 1100000,
- .max_uV = 3300000,
.update_bank = 0x04,
.update_reg = 0x0a,
.update_mask = 0x03,
.voltage_bank = 0x04,
.voltage_reg = 0x21,
.voltage_mask = 0x07,
- .voltages = ldo_vaux3_voltages,
- .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages),
},
[AB8500_LDO_INTCORE] = {
.desc = {
.id = AB8500_LDO_INTCORE,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
+ .volt_table = ldo_vintcore_voltages,
},
- .min_uV = 1100000,
- .max_uV = 3300000,
.update_bank = 0x03,
.update_reg = 0x80,
.update_mask = 0x44,
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltages = ldo_vintcore_voltages,
- .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages),
},
/*
.id = AB8500_LDO_TVOUT,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 2000000,
},
.delay = 10000,
- .fixed_uV = 2000000,
.update_bank = 0x03,
.update_reg = 0x80,
.update_mask = 0x82,
.id = AB8500_LDO_USB,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 3300000,
},
- .fixed_uV = 3300000,
.update_bank = 0x03,
.update_reg = 0x82,
.update_mask = 0x03,
.id = AB8500_LDO_AUDIO,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 2000000,
},
- .fixed_uV = 2000000,
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x02,
.id = AB8500_LDO_ANAMIC1,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 2050000,
},
- .fixed_uV = 2050000,
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x08,
.id = AB8500_LDO_ANAMIC2,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 2050000,
},
- .fixed_uV = 2050000,
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x10,
.id = AB8500_LDO_DMIC,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 1800000,
},
- .fixed_uV = 1800000,
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x04,
.id = AB8500_LDO_ANA,
.owner = THIS_MODULE,
.n_voltages = 1,
+ .min_uV = 1200000,
},
- .fixed_uV = 1200000,
.update_bank = 0x04,
.update_reg = 0x06,
.update_mask = 0x0c,
if (info->desc.id == AB8500_LDO_AUX3) {
info->desc.n_voltages =
ARRAY_SIZE(ldo_vauxn_voltages);
- info->voltages = ldo_vauxn_voltages;
- info->voltages_len =
- ARRAY_SIZE(ldo_vauxn_voltages);
+ info->desc.volt_table = ldo_vauxn_voltages;
info->voltage_mask = 0xf;
}
}
unsigned short data;
int ret;
- if (min_uA > chip->max_uA || min_uA < chip->min_uA)
- return -EINVAL;
- if (max_uA > chip->max_uA || max_uA < chip->min_uA)
+ if (min_uA < chip->min_uA)
+ min_uA = chip->min_uA;
+ if (max_uA > chip->max_uA)
+ max_uA = chip->max_uA;
+
+ if (min_uA > chip->max_uA || max_uA < chip->min_uA)
return -EINVAL;
selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level,
struct regulator_init_data *initdata;
};
-static int anatop_set_voltage(struct regulator_dev *reg, int min_uV,
- int max_uV, unsigned *selector)
+static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
- u32 val, sel, mask;
- int uv;
-
- uv = min_uV;
- dev_dbg(®->dev, "%s: uv %d, min %d, max %d\n", __func__,
- uv, anatop_reg->min_voltage,
- anatop_reg->max_voltage);
-
- if (uv < anatop_reg->min_voltage) {
- if (max_uV > anatop_reg->min_voltage)
- uv = anatop_reg->min_voltage;
- else
- return -EINVAL;
- }
+ u32 val, mask;
if (!anatop_reg->control_reg)
return -ENOTSUPP;
- sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000);
- if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage)
- return -EINVAL;
- val = anatop_reg->min_bit_val + sel;
- *selector = sel;
+ val = anatop_reg->min_bit_val + selector;
dev_dbg(®->dev, "%s: calculated val %d\n", __func__, val);
mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
anatop_reg->vol_bit_shift;
return val - anatop_reg->min_bit_val;
}
-static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector)
-{
- struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
- int uv;
-
- uv = anatop_reg->min_voltage + selector * 25000;
- dev_dbg(®->dev, "vddio = %d, selector = %u\n", uv, selector);
-
- return uv;
-}
-
static struct regulator_ops anatop_rops = {
- .set_voltage = anatop_set_voltage,
+ .set_voltage_sel = anatop_set_voltage_sel,
.get_voltage_sel = anatop_get_voltage_sel,
- .list_voltage = anatop_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
};
static int __devinit anatop_regulator_probe(struct platform_device *pdev)
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage)
/ 25000 + 1;
+ rdesc->min_uV = sreg->min_voltage;
+ rdesc->uV_step = 25000;
config.dev = &pdev->dev;
config.init_data = initdata;
--- /dev/null
+/*
+ * arizona-ldo1.c -- LDO1 supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+struct arizona_ldo1 {
+ struct regulator_dev *regulator;
+ struct arizona *arizona;
+
+ struct regulator_consumer_supply supply;
+ struct regulator_init_data init_data;
+};
+
+static struct regulator_ops arizona_ldo1_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_ldo1 = {
+ .name = "LDO1",
+ .supply_name = "LDOVDD",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &arizona_ldo1_ops,
+
+ .vsel_reg = ARIZONA_LDO1_CONTROL_1,
+ .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
+ .min_uV = 900000,
+ .uV_step = 50000,
+ .n_voltages = 7,
+
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_ldo1_default = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_ldo1_probe(struct platform_device *pdev)
+{
+ struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct arizona_ldo1 *ldo1;
+ int ret;
+
+ ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+ if (ldo1 == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ ldo1->arizona = arizona;
+
+ /*
+ * Since the chip usually supplies itself we provide some
+ * default init_data for it. This will be overridden with
+ * platform data if provided.
+ */
+ ldo1->init_data = arizona_ldo1_default;
+ ldo1->init_data.consumer_supplies = &ldo1->supply;
+ ldo1->supply.supply = "DCVDD";
+ ldo1->supply.dev_name = dev_name(arizona->dev);
+
+ config.dev = arizona->dev;
+ config.driver_data = ldo1;
+ config.regmap = arizona->regmap;
+ config.ena_gpio = arizona->pdata.ldoena;
+
+ if (arizona->pdata.ldo1)
+ config.init_data = arizona->pdata.ldo1;
+ else
+ config.init_data = &ldo1->init_data;
+
+ ldo1->regulator = regulator_register(&arizona_ldo1, &config);
+ if (IS_ERR(ldo1->regulator)) {
+ ret = PTR_ERR(ldo1->regulator);
+ dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n",
+ ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, ldo1);
+
+ return 0;
+}
+
+static __devexit int arizona_ldo1_remove(struct platform_device *pdev)
+{
+ struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
+
+ regulator_unregister(ldo1->regulator);
+
+ return 0;
+}
+
+static struct platform_driver arizona_ldo1_driver = {
+ .probe = arizona_ldo1_probe,
+ .remove = __devexit_p(arizona_ldo1_remove),
+ .driver = {
+ .name = "arizona-ldo1",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(arizona_ldo1_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona LDO1 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-ldo1");
--- /dev/null
+/*
+ * arizona-micsupp.c -- Microphone supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+#define ARIZONA_MICSUPP_MAX_SELECTOR 0x1f
+
+struct arizona_micsupp {
+ struct regulator_dev *regulator;
+ struct arizona *arizona;
+
+ struct regulator_consumer_supply supply;
+ struct regulator_init_data init_data;
+};
+
+static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector > ARIZONA_MICSUPP_MAX_SELECTOR)
+ return -EINVAL;
+
+ if (selector == ARIZONA_MICSUPP_MAX_SELECTOR)
+ return 3300000;
+ else
+ return (selector * 50000) + 1700000;
+}
+
+static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ unsigned int voltage;
+ int selector;
+
+ if (min_uV < 1700000)
+ min_uV = 1700000;
+
+ if (min_uV > 3200000)
+ selector = ARIZONA_MICSUPP_MAX_SELECTOR;
+ else
+ selector = DIV_ROUND_UP(min_uV - 1700000, 50000);
+
+ if (selector < 0)
+ return -EINVAL;
+
+ voltage = arizona_micsupp_list_voltage(rdev, selector);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return selector;
+}
+
+static struct regulator_ops arizona_micsupp_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+
+ .list_voltage = arizona_micsupp_list_voltage,
+ .map_voltage = arizona_micsupp_map_voltage,
+
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_micsupp = {
+ .name = "MICVDD",
+ .supply_name = "CPVDD",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = ARIZONA_MICSUPP_MAX_SELECTOR + 1,
+ .ops = &arizona_micsupp_ops,
+
+ .vsel_reg = ARIZONA_LDO2_CONTROL_1,
+ .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
+ .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
+ .enable_mask = ARIZONA_CPMIC_ENA,
+
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_micsupp_default = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_VOLTAGE,
+ .min_uV = 1700000,
+ .max_uV = 3300000,
+ },
+
+ .num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_micsupp_probe(struct platform_device *pdev)
+{
+ struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct arizona_micsupp *micsupp;
+ int ret;
+
+ micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+ if (micsupp == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ micsupp->arizona = arizona;
+
+ /*
+ * Since the chip usually supplies itself we provide some
+ * default init_data for it. This will be overridden with
+ * platform data if provided.
+ */
+ micsupp->init_data = arizona_micsupp_default;
+ micsupp->init_data.consumer_supplies = &micsupp->supply;
+ micsupp->supply.supply = "MICVDD";
+ micsupp->supply.dev_name = dev_name(arizona->dev);
+
+ config.dev = arizona->dev;
+ config.driver_data = micsupp;
+ config.regmap = arizona->regmap;
+
+ if (arizona->pdata.micvdd)
+ config.init_data = arizona->pdata.micvdd;
+ else
+ config.init_data = &micsupp->init_data;
+
+ /* Default to regulated mode until the API supports bypass */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,
+ ARIZONA_CPMIC_BYPASS, 0);
+
+ micsupp->regulator = regulator_register(&arizona_micsupp, &config);
+ if (IS_ERR(micsupp->regulator)) {
+ ret = PTR_ERR(micsupp->regulator);
+ dev_err(arizona->dev, "Failed to register mic supply: %d\n",
+ ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, micsupp);
+
+ return 0;
+}
+
+static __devexit int arizona_micsupp_remove(struct platform_device *pdev)
+{
+ struct arizona_micsupp *micsupp = platform_get_drvdata(pdev);
+
+ regulator_unregister(micsupp->regulator);
+
+ return 0;
+}
+
+static struct platform_driver arizona_micsupp_driver = {
+ .probe = arizona_micsupp_probe,
+ .remove = __devexit_p(arizona_micsupp_remove),
+ .driver = {
+ .name = "arizona-micsupp",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(arizona_micsupp_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona microphone supply driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-micsupp");
#include <linux/mutex.h>
#include <linux/suspend.h>
#include <linux/delay.h>
+#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
}
}
+ if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+ ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to set ramp_delay\n");
+ goto out;
+ }
+ }
+
print_constraints(rdev);
return 0;
out:
static int _regulator_get_enable_time(struct regulator_dev *rdev)
{
if (!rdev->desc->ops->enable_time)
- return 0;
+ return rdev->desc->enable_time;
return rdev->desc->ops->enable_time(rdev);
}
}
EXPORT_SYMBOL_GPL(devm_regulator_put);
+static int _regulator_do_enable(struct regulator_dev *rdev)
+{
+ int ret, delay;
+
+ /* Query before enabling in case configuration dependent. */
+ ret = _regulator_get_enable_time(rdev);
+ if (ret >= 0) {
+ delay = ret;
+ } else {
+ rdev_warn(rdev, "enable_time() failed: %d\n", ret);
+ delay = 0;
+ }
+
+ trace_regulator_enable(rdev_get_name(rdev));
+
+ if (rdev->ena_gpio) {
+ gpio_set_value_cansleep(rdev->ena_gpio,
+ !rdev->ena_gpio_invert);
+ rdev->ena_gpio_state = 1;
+ } else if (rdev->desc->ops->enable) {
+ ret = rdev->desc->ops->enable(rdev);
+ if (ret < 0)
+ return ret;
+ } else {
+ return -EINVAL;
+ }
+
+ /* Allow the regulator to ramp; it would be useful to extend
+ * this for bulk operations so that the regulators can ramp
+ * together. */
+ trace_regulator_enable_delay(rdev_get_name(rdev));
+
+ if (delay >= 1000) {
+ mdelay(delay / 1000);
+ udelay(delay % 1000);
+ } else if (delay) {
+ udelay(delay);
+ }
+
+ trace_regulator_enable_complete(rdev_get_name(rdev));
+
+ return 0;
+}
+
/* locks held by regulator_enable() */
static int _regulator_enable(struct regulator_dev *rdev)
{
- int ret, delay;
+ int ret;
/* check voltage and requested load before enabling */
if (rdev->constraints &&
if (!_regulator_can_change_status(rdev))
return -EPERM;
- if (!rdev->desc->ops->enable)
- return -EINVAL;
-
- /* Query before enabling in case configuration
- * dependent. */
- ret = _regulator_get_enable_time(rdev);
- if (ret >= 0) {
- delay = ret;
- } else {
- rdev_warn(rdev, "enable_time() failed: %d\n",
- ret);
- delay = 0;
- }
-
- trace_regulator_enable(rdev_get_name(rdev));
-
- /* Allow the regulator to ramp; it would be useful
- * to extend this for bulk operations so that the
- * regulators can ramp together. */
- ret = rdev->desc->ops->enable(rdev);
+ ret = _regulator_do_enable(rdev);
if (ret < 0)
return ret;
- trace_regulator_enable_delay(rdev_get_name(rdev));
-
- if (delay >= 1000) {
- mdelay(delay / 1000);
- udelay(delay % 1000);
- } else if (delay) {
- udelay(delay);
- }
-
- trace_regulator_enable_complete(rdev_get_name(rdev));
-
} else if (ret < 0) {
rdev_err(rdev, "is_enabled() failed: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_enable);
+static int _regulator_do_disable(struct regulator_dev *rdev)
+{
+ int ret;
+
+ trace_regulator_disable(rdev_get_name(rdev));
+
+ if (rdev->ena_gpio) {
+ gpio_set_value_cansleep(rdev->ena_gpio,
+ rdev->ena_gpio_invert);
+ rdev->ena_gpio_state = 0;
+
+ } else if (rdev->desc->ops->disable) {
+ ret = rdev->desc->ops->disable(rdev);
+ if (ret != 0)
+ return ret;
+ }
+
+ trace_regulator_disable_complete(rdev_get_name(rdev));
+
+ _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+ NULL);
+ return 0;
+}
+
/* locks held by regulator_disable() */
static int _regulator_disable(struct regulator_dev *rdev)
{
(rdev->constraints && !rdev->constraints->always_on)) {
/* we are last user */
- if (_regulator_can_change_status(rdev) &&
- rdev->desc->ops->disable) {
- trace_regulator_disable(rdev_get_name(rdev));
-
- ret = rdev->desc->ops->disable(rdev);
+ if (_regulator_can_change_status(rdev)) {
+ ret = _regulator_do_disable(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to disable\n");
return ret;
}
-
- trace_regulator_disable_complete(rdev_get_name(rdev));
-
- _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
- NULL);
}
rdev->use_count = 0;
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
+ /* A GPIO control always takes precedence */
+ if (rdev->ena_gpio)
+ return rdev->ena_gpio_state;
+
/* If we don't know then assume that the regulator is always on */
if (!rdev->desc->ops->is_enabled)
return 1;
{
int ret, voltage;
+ /* Allow uV_step to be 0 for fixed voltage */
+ if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+ if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+ return 0;
+ else
+ return -EINVAL;
+ }
+
if (!rdev->desc->uV_step) {
BUG_ON(!rdev->desc->uV_step);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
+/**
+ *regulator_set_voltage_time_sel - get raise/fall time
+ * @regulator: regulator source
+ * @old_selector: selector for starting voltage
+ * @new_selector: selector for target voltage
+ *
+ * Provided with the starting and target voltage selectors, this function
+ * returns time in microseconds required to rise or fall to this new voltage
+ *
+ * Drivers providing ramp_delay in regulation_constraints can use this as their
+ * set_voltage_time_sel() operation.
+ */
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ unsigned int ramp_delay = 0;
+ int old_volt, new_volt;
+
+ if (rdev->constraints->ramp_delay)
+ ramp_delay = rdev->constraints->ramp_delay;
+ else if (rdev->desc->ramp_delay)
+ ramp_delay = rdev->desc->ramp_delay;
+
+ if (ramp_delay == 0) {
+ rdev_warn(rdev, "ramp_delay not set\n");
+ return 0;
+ }
+
+ /* sanity check */
+ if (!rdev->desc->ops->list_voltage)
+ return -EINVAL;
+
+ old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
+ new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);
+
+ return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
+
/**
* regulator_sync_voltage - re-apply last regulator output voltage
* @regulator: regulator source
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator *consumer;
- int ret, output_uV, input_uV, total_uA_load = 0;
+ int ret, output_uV, input_uV = 0, total_uA_load = 0;
unsigned int mode;
+ if (rdev->supply)
+ input_uV = regulator_get_voltage(rdev->supply);
+
mutex_lock(&rdev->mutex);
/*
goto out;
}
- /* get input voltage */
- input_uV = 0;
- if (rdev->supply)
- input_uV = regulator_get_voltage(rdev->supply);
+ /* No supply? Use constraint voltage */
if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
dev_set_drvdata(&rdev->dev, rdev);
+ if (config->ena_gpio) {
+ ret = gpio_request_one(config->ena_gpio,
+ GPIOF_DIR_OUT | config->ena_gpio_flags,
+ rdev_get_name(rdev));
+ if (ret != 0) {
+ rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
+ config->ena_gpio, ret);
+ goto clean;
+ }
+
+ rdev->ena_gpio = config->ena_gpio;
+ rdev->ena_gpio_invert = config->ena_gpio_invert;
+
+ if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
+ rdev->ena_gpio_state = 1;
+
+ if (rdev->ena_gpio_invert)
+ rdev->ena_gpio_state = !rdev->ena_gpio_state;
+ }
+
/* set regulator constraints */
if (init_data)
constraints = &init_data->constraints;
scrub:
if (rdev->supply)
regulator_put(rdev->supply);
+ if (rdev->ena_gpio)
+ gpio_free(rdev->ena_gpio);
kfree(rdev->constraints);
device_unregister(&rdev->dev);
/* device core frees rdev */
unset_regulator_supplies(rdev);
list_del(&rdev->list);
kfree(rdev->constraints);
+ if (rdev->ena_gpio)
+ gpio_free(rdev->ena_gpio);
device_unregister(&rdev->dev);
mutex_unlock(®ulator_list_mutex);
}
struct device *da9034_dev = to_da903x_dev(rdev);
uint8_t val, mask;
+ if (rdev->desc->n_voltages == 1)
+ return -EINVAL;
+
val = selector << info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
uint8_t val, mask;
int ret;
+ if (rdev->desc->n_voltages == 1)
+ return 0;
+
ret = da903x_read(da9034_dev, info->vol_reg, &val);
if (ret)
return ret;
if (!nproot)
return -ENODEV;
- for (np = of_get_next_child(nproot, NULL); np;
- np = of_get_next_child(nproot, np)) {
+ for_each_child_of_node(nproot, np) {
if (!of_node_cmp(np->name,
regulator->info->reg_desc.name)) {
config.init_data = of_get_regulator_init_data(
&pdev->dev, np);
+ config.of_node = np;
break;
}
}
struct regulator_desc desc;
struct regulator_dev *dev;
int microvolts;
- int gpio;
- unsigned startup_delay;
- bool enable_high;
- bool is_enabled;
};
config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
GFP_KERNEL);
if (!config)
- return NULL;
+ return ERR_PTR(-ENOMEM);
config->init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!config->init_data)
- return NULL;
+ return ERR_PTR(-EINVAL);
init_data = config->init_data;
init_data->constraints.apply_uV = 0;
} else {
dev_err(dev,
"Fixed regulator specified with variable voltages\n");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
if (init_data->constraints.boot_on)
config->enabled_at_boot = true;
config->gpio = of_get_named_gpio(np, "gpio", 0);
+ /*
+ * of_get_named_gpio() currently returns ENODEV rather than
+ * EPROBE_DEFER. This code attempts to be compatible with both
+ * for now; the ENODEV check can be removed once the API is fixed.
+ * of_get_named_gpio() doesn't differentiate between a missing
+ * property (which would be fine here, since the GPIO is optional)
+ * and some other error. Patches have been posted for both issues.
+ * Once they are check in, we should replace this with:
+ * if (config->gpio < 0 && config->gpio != -ENOENT)
+ */
+ if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
+ return ERR_PTR(-EPROBE_DEFER);
+
delay = of_get_property(np, "startup-delay-us", NULL);
if (delay)
config->startup_delay = be32_to_cpu(*delay);
if (of_find_property(np, "gpio-open-drain", NULL))
config->gpio_is_open_drain = true;
- return config;
-}
-
-static int fixed_voltage_is_enabled(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- return data->is_enabled;
-}
-
-static int fixed_voltage_enable(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- gpio_set_value_cansleep(data->gpio, data->enable_high);
- data->is_enabled = true;
-
- return 0;
-}
-
-static int fixed_voltage_disable(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- gpio_set_value_cansleep(data->gpio, !data->enable_high);
- data->is_enabled = false;
-
- return 0;
-}
+ if (of_find_property(np, "vin-supply", NULL))
+ config->input_supply = "vin";
-static int fixed_voltage_enable_time(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- return data->startup_delay;
+ return config;
}
static int fixed_voltage_get_voltage(struct regulator_dev *dev)
return data->microvolts;
}
-static struct regulator_ops fixed_voltage_gpio_ops = {
- .is_enabled = fixed_voltage_is_enabled,
- .enable = fixed_voltage_enable,
- .disable = fixed_voltage_disable,
- .enable_time = fixed_voltage_enable_time,
- .get_voltage = fixed_voltage_get_voltage,
- .list_voltage = fixed_voltage_list_voltage,
-};
-
static struct regulator_ops fixed_voltage_ops = {
.get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage,
struct regulator_config cfg = { };
int ret;
- if (pdev->dev.of_node)
+ if (pdev->dev.of_node) {
config = of_get_fixed_voltage_config(&pdev->dev);
- else
+ if (IS_ERR(config))
+ return PTR_ERR(config);
+ } else {
config = pdev->dev.platform_data;
+ }
if (!config)
return -ENOMEM;
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
+ drvdata->desc.ops = &fixed_voltage_ops;
- if (config->microvolts)
- drvdata->desc.n_voltages = 1;
+ drvdata->desc.enable_time = config->startup_delay;
- drvdata->microvolts = config->microvolts;
- drvdata->gpio = config->gpio;
- drvdata->startup_delay = config->startup_delay;
-
- if (gpio_is_valid(config->gpio)) {
- int gpio_flag;
- drvdata->enable_high = config->enable_high;
-
- /* FIXME: Remove below print warning
- *
- * config->gpio must be set to -EINVAL by platform code if
- * GPIO control is not required. However, early adopters
- * not requiring GPIO control may forget to initialize
- * config->gpio to -EINVAL. This will cause GPIO 0 to be used
- * for GPIO control.
- *
- * This warning will be removed once there are a couple of users
- * for this driver.
- */
- if (!config->gpio)
- dev_warn(&pdev->dev,
- "using GPIO 0 for regulator enable control\n");
-
- /*
- * set output direction without changing state
- * to prevent glitch
- */
- drvdata->is_enabled = config->enabled_at_boot;
- ret = drvdata->is_enabled ?
- config->enable_high : !config->enable_high;
- gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-
- if (config->gpio_is_open_drain)
- gpio_flag |= GPIOF_OPEN_DRAIN;
-
- ret = gpio_request_one(config->gpio, gpio_flag,
- config->supply_name);
- if (ret) {
+ if (config->input_supply) {
+ drvdata->desc.supply_name = kstrdup(config->input_supply,
+ GFP_KERNEL);
+ if (!drvdata->desc.supply_name) {
dev_err(&pdev->dev,
- "Could not obtain regulator enable GPIO %d: %d\n",
- config->gpio, ret);
+ "Failed to allocate input supply\n");
+ ret = -ENOMEM;
goto err_name;
}
+ }
+
+ if (config->microvolts)
+ drvdata->desc.n_voltages = 1;
- drvdata->desc.ops = &fixed_voltage_gpio_ops;
+ drvdata->microvolts = config->microvolts;
+ if (config->gpio >= 0)
+ cfg.ena_gpio = config->gpio;
+ cfg.ena_gpio_invert = !config->enable_high;
+ if (config->enabled_at_boot) {
+ if (config->enable_high) {
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ } else {
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ }
} else {
- drvdata->desc.ops = &fixed_voltage_ops;
+ if (config->enable_high) {
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ } else {
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ }
}
+ if (config->gpio_is_open_drain)
+ cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
- goto err_gpio;
+ goto err_input;
}
platform_set_drvdata(pdev, drvdata);
return 0;
-err_gpio:
- if (gpio_is_valid(config->gpio))
- gpio_free(config->gpio);
+err_input:
+ kfree(drvdata->desc.supply_name);
err_name:
kfree(drvdata->desc.name);
err:
struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
regulator_unregister(drvdata->dev);
- if (gpio_is_valid(drvdata->gpio))
- gpio_free(drvdata->gpio);
+ kfree(drvdata->desc.supply_name);
kfree(drvdata->desc.name);
return 0;
{},
};
MODULE_DEVICE_TABLE(of, fixed_of_match);
-#else
-#define fixed_of_match NULL
#endif
static struct platform_driver regulator_fixed_voltage_driver = {
.driver = {
.name = "reg-fixed-voltage",
.owner = THIS_MODULE,
- .of_match_table = fixed_of_match,
+ .of_match_table = of_match_ptr(fixed_of_match),
},
};
struct regulator_desc desc;
struct regulator_dev *dev;
- int enable_gpio;
- bool enable_high;
- bool is_enabled;
- unsigned startup_delay;
-
struct gpio *gpios;
int nr_gpios;
int state;
};
-static int gpio_regulator_is_enabled(struct regulator_dev *dev)
-{
- struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
- return data->is_enabled;
-}
-
-static int gpio_regulator_enable(struct regulator_dev *dev)
-{
- struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
- if (gpio_is_valid(data->enable_gpio)) {
- gpio_set_value_cansleep(data->enable_gpio, data->enable_high);
- data->is_enabled = true;
- }
-
- return 0;
-}
-
-static int gpio_regulator_disable(struct regulator_dev *dev)
-{
- struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
- if (gpio_is_valid(data->enable_gpio)) {
- gpio_set_value_cansleep(data->enable_gpio, !data->enable_high);
- data->is_enabled = false;
- }
-
- return 0;
-}
-
-static int gpio_regulator_enable_time(struct regulator_dev *dev)
-{
- struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
- return data->startup_delay;
-}
-
static int gpio_regulator_get_value(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
}
static struct regulator_ops gpio_regulator_voltage_ops = {
- .is_enabled = gpio_regulator_is_enabled,
- .enable = gpio_regulator_enable,
- .disable = gpio_regulator_disable,
- .enable_time = gpio_regulator_enable_time,
.get_voltage = gpio_regulator_get_value,
.set_voltage = gpio_regulator_set_voltage,
.list_voltage = gpio_regulator_list_voltage,
};
static struct regulator_ops gpio_regulator_current_ops = {
- .is_enabled = gpio_regulator_is_enabled,
- .enable = gpio_regulator_enable,
- .disable = gpio_regulator_disable,
- .enable_time = gpio_regulator_enable_time,
.get_current_limit = gpio_regulator_get_value,
.set_current_limit = gpio_regulator_set_current_limit,
};
drvdata->nr_states = config->nr_states;
drvdata->desc.owner = THIS_MODULE;
+ drvdata->desc.enable_time = config->startup_delay;
/* handle regulator type*/
switch (config->type) {
break;
}
- drvdata->enable_gpio = config->enable_gpio;
- drvdata->startup_delay = config->startup_delay;
-
- if (gpio_is_valid(config->enable_gpio)) {
- drvdata->enable_high = config->enable_high;
-
- ret = gpio_request(config->enable_gpio, config->supply_name);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not obtain regulator enable GPIO %d: %d\n",
- config->enable_gpio, ret);
- goto err_memstate;
- }
-
- /* set output direction without changing state
- * to prevent glitch
- */
- if (config->enabled_at_boot) {
- drvdata->is_enabled = true;
- ret = gpio_direction_output(config->enable_gpio,
- config->enable_high);
- } else {
- drvdata->is_enabled = false;
- ret = gpio_direction_output(config->enable_gpio,
- !config->enable_high);
- }
-
- if (ret) {
- dev_err(&pdev->dev,
- "Could not configure regulator enable GPIO %d direction: %d\n",
- config->enable_gpio, ret);
- goto err_enablegpio;
- }
- } else {
- /* Regulator without GPIO control is considered
- * always enabled
- */
- drvdata->is_enabled = true;
- }
-
drvdata->nr_gpios = config->nr_gpios;
ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
if (ret) {
dev_err(&pdev->dev,
"Could not obtain regulator setting GPIOs: %d\n", ret);
- goto err_enablegpio;
+ goto err_memstate;
}
/* build initial state from gpio init data. */
cfg.init_data = config->init_data;
cfg.driver_data = drvdata;
+ if (config->enable_gpio >= 0)
+ cfg.ena_gpio = config->enable_gpio;
+ cfg.ena_gpio_invert = !config->enable_high;
+ if (config->enabled_at_boot) {
+ if (config->enable_high)
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ else
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ } else {
+ if (config->enable_high)
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ else
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ }
+
drvdata->dev = regulator_register(&drvdata->desc, &cfg);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
err_stategpio:
gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
-err_enablegpio:
- if (gpio_is_valid(config->enable_gpio))
- gpio_free(config->enable_gpio);
err_memstate:
kfree(drvdata->states);
err_memgpio:
kfree(drvdata->states);
kfree(drvdata->gpios);
- if (gpio_is_valid(drvdata->enable_gpio))
- gpio_free(drvdata->enable_gpio);
-
kfree(drvdata->desc.name);
return 0;
static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
{
- int id = rdev_get_id(dev);
- return (id == 1) ? 1100000 : 1300000;
-}
-
-static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
-{
- int id = rdev_get_id(dev);
- return (id == 1) ? 1100000 : 1300000;
+ return dev->desc->min_uV;
}
static struct regulator_ops isl_fixed_ops = {
.get_voltage = isl6271a_get_fixed_voltage,
- .list_voltage = isl6271a_list_fixed_voltage,
+ .list_voltage = regulator_list_voltage_linear,
};
static const struct regulator_desc isl_rd[] = {
.ops = &isl_fixed_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = 1100000,
}, {
.name = "LDO2",
.id = 2,
.ops = &isl_fixed_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .min_uV = 1300000,
},
};
#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
-static const int buck_voltage_map[] = {
- 0, 800, 850, 900, 950, 1000, 1050, 1100,
- 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
- 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
- 3000, 3300,
+static const unsigned int buck_voltage_map[] = {
+ 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+ 3000000, 3300000,
};
#define BUCK_TARGET_VOL_MASK 0x3f
#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
#define LDO_VOL_CONTR_MASK 0x0f
-static const int ldo45_voltage_map[] = {
- 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
- 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo45_voltage_map[] = {
+ 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+ 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
};
-static const int ldo123_voltage_map[] = {
- 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
- 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo123_voltage_map[] = {
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
};
-static const int *ldo_voltage_map[] = {
- ldo123_voltage_map, /* LDO1 */
- ldo123_voltage_map, /* LDO2 */
- ldo123_voltage_map, /* LDO3 */
- ldo45_voltage_map, /* LDO4 */
- ldo45_voltage_map, /* LDO5 */
-};
-
-#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
-
#define LDO_VOL_MIN_IDX 0x00
#define LDO_VOL_MAX_IDX 0x0f
-static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
- int ldo = rdev_get_id(dev) - LP3971_LDO1;
-
- if (index > LDO_VOL_MAX_IDX)
- return -EINVAL;
-
- return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
- return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
+ return dev->desc->volt_table[val];
}
static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
}
static struct regulator_ops lp3971_ldo_ops = {
- .list_voltage = lp3971_ldo_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.is_enabled = lp3971_ldo_is_enabled,
.enable = lp3971_ldo_enable,
.disable = lp3971_ldo_disable,
.set_voltage_sel = lp3971_ldo_set_voltage_sel,
};
-static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
- if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX)
- return -EINVAL;
-
- return 1000 * buck_voltage_map[index];
-}
-
static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
reg &= BUCK_TARGET_VOL_MASK;
if (reg <= BUCK_TARGET_VOL_MAX_IDX)
- val = 1000 * buck_voltage_map[reg];
+ val = buck_voltage_map[reg];
else {
val = 0;
dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
}
static struct regulator_ops lp3971_dcdc_ops = {
- .list_voltage = lp3971_dcdc_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.is_enabled = lp3971_dcdc_is_enabled,
.enable = lp3971_dcdc_enable,
.disable = lp3971_dcdc_disable,
.id = LP3971_LDO1,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+ .volt_table = ldo123_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_LDO2,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+ .volt_table = ldo123_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_LDO3,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+ .volt_table = ldo123_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_LDO4,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+ .volt_table = ldo45_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_LDO5,
.ops = &lp3971_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+ .volt_table = ldo45_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_DCDC1,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
+ .volt_table = buck_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_DCDC2,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
+ .volt_table = buck_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3971_DCDC3,
.ops = &lp3971_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck_voltage_map),
+ .volt_table = buck_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
#define LP3972_OVER2_LDO4_EN BIT(4)
#define LP3972_OVER1_S_EN BIT(2)
-static const int ldo1_voltage_map[] = {
- 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
- 1900, 1925, 1950, 1975, 2000,
+static const unsigned int ldo1_voltage_map[] = {
+ 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+ 1900000, 1925000, 1950000, 1975000, 2000000,
};
-static const int ldo23_voltage_map[] = {
- 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
- 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo23_voltage_map[] = {
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
};
-static const int ldo4_voltage_map[] = {
- 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
- 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo4_voltage_map[] = {
+ 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+ 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
};
-static const int ldo5_voltage_map[] = {
- 0, 0, 0, 0, 0, 850, 875, 900,
- 925, 950, 975, 1000, 1025, 1050, 1075, 1100,
- 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
- 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int ldo5_voltage_map[] = {
+ 0, 0, 0, 0, 0, 850000, 875000, 900000,
+ 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+ 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+ 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
-static const int buck1_voltage_map[] = {
- 725, 750, 775, 800, 825, 850, 875, 900,
- 925, 950, 975, 1000, 1025, 1050, 1075, 1100,
- 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
- 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int buck1_voltage_map[] = {
+ 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000,
+ 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+ 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+ 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
-static const int buck23_voltage_map[] = {
- 0, 800, 850, 900, 950, 1000, 1050, 1100,
- 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
- 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
- 3000, 3300,
-};
-
-static const int *ldo_voltage_map[] = {
- ldo1_voltage_map,
- ldo23_voltage_map,
- ldo23_voltage_map,
- ldo4_voltage_map,
- ldo5_voltage_map,
-};
-
-static const int *buck_voltage_map[] = {
- buck1_voltage_map,
- buck23_voltage_map,
- buck23_voltage_map,
+static const unsigned int buck23_voltage_map[] = {
+ 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+ 3000000, 3300000,
};
static const int ldo_output_enable_mask[] = {
LP3972_B3TV_REG,
};
-#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
-#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
#define LP3972_BUCK_VOL_MASK 0x1f
return ret;
}
-static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
- int ldo = rdev_get_id(dev) - LP3972_LDO1;
-
- if (index < LP3972_LDO_VOL_MIN_IDX(ldo) ||
- index > LP3972_LDO_VOL_MAX_IDX(ldo))
- return -EINVAL;
-
- return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
- return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
+ return dev->desc->volt_table[val];
}
static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
}
static struct regulator_ops lp3972_ldo_ops = {
- .list_voltage = lp3972_ldo_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.is_enabled = lp3972_ldo_is_enabled,
.enable = lp3972_ldo_enable,
.disable = lp3972_ldo_disable,
.set_voltage_sel = lp3972_ldo_set_voltage_sel,
};
-static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
- int buck = rdev_get_id(dev) - LP3972_DCDC1;
-
- if (index < LP3972_BUCK_VOL_MIN_IDX(buck) ||
- index > LP3972_BUCK_VOL_MAX_IDX(buck))
- return -EINVAL;
-
- return 1000 * buck_voltage_map[buck][index];
-}
-
static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
reg &= LP3972_BUCK_VOL_MASK;
if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
- val = 1000 * buck_voltage_map[buck][reg];
+ val = dev->desc->volt_table[reg];
else {
val = 0;
dev_warn(&dev->dev, "chip reported incorrect voltage value."
}
static struct regulator_ops lp3972_dcdc_ops = {
- .list_voltage = lp3972_dcdc_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.is_enabled = lp3972_dcdc_is_enabled,
.enable = lp3972_dcdc_enable,
.disable = lp3972_dcdc_disable,
.id = LP3972_LDO1,
.ops = &lp3972_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
+ .volt_table = ldo1_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_LDO2,
.ops = &lp3972_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+ .volt_table = ldo23_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_LDO3,
.ops = &lp3972_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+ .volt_table = ldo23_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_LDO4,
.ops = &lp3972_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
+ .volt_table = ldo4_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_LDO5,
.ops = &lp3972_ldo_ops,
.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
+ .volt_table = ldo5_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_DCDC1,
.ops = &lp3972_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck1_voltage_map),
+ .volt_table = buck1_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_DCDC2,
.ops = &lp3972_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+ .volt_table = buck23_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.id = LP3972_DCDC3,
.ops = &lp3972_dcdc_ops,
.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+ .volt_table = buck23_voltage_map,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
--- /dev/null
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/regulator/lp872x.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+
+/* Registers : LP8720/8725 shared */
+#define LP872X_GENERAL_CFG 0x00
+#define LP872X_LDO1_VOUT 0x01
+#define LP872X_LDO2_VOUT 0x02
+#define LP872X_LDO3_VOUT 0x03
+#define LP872X_LDO4_VOUT 0x04
+#define LP872X_LDO5_VOUT 0x05
+
+/* Registers : LP8720 */
+#define LP8720_BUCK_VOUT1 0x06
+#define LP8720_BUCK_VOUT2 0x07
+#define LP8720_ENABLE 0x08
+
+/* Registers : LP8725 */
+#define LP8725_LILO1_VOUT 0x06
+#define LP8725_LILO2_VOUT 0x07
+#define LP8725_BUCK1_VOUT1 0x08
+#define LP8725_BUCK1_VOUT2 0x09
+#define LP8725_BUCK2_VOUT1 0x0A
+#define LP8725_BUCK2_VOUT2 0x0B
+#define LP8725_BUCK_CTRL 0x0C
+#define LP8725_LDO_CTRL 0x0D
+
+/* Mask/shift : LP8720/LP8725 shared */
+#define LP872X_VOUT_M 0x1F
+#define LP872X_START_DELAY_M 0xE0
+#define LP872X_START_DELAY_S 5
+#define LP872X_EN_LDO1_M BIT(0)
+#define LP872X_EN_LDO2_M BIT(1)
+#define LP872X_EN_LDO3_M BIT(2)
+#define LP872X_EN_LDO4_M BIT(3)
+#define LP872X_EN_LDO5_M BIT(4)
+
+/* Mask/shift : LP8720 */
+#define LP8720_TIMESTEP_S 0 /* Addr 00h */
+#define LP8720_TIMESTEP_M BIT(0)
+#define LP8720_EXT_DVS_M BIT(2)
+#define LP8720_BUCK_FPWM_S 5 /* Addr 07h */
+#define LP8720_BUCK_FPWM_M BIT(5)
+#define LP8720_EN_BUCK_M BIT(5) /* Addr 08h */
+#define LP8720_DVS_SEL_M BIT(7)
+
+/* Mask/shift : LP8725 */
+#define LP8725_TIMESTEP_M 0xC0 /* Addr 00h */
+#define LP8725_TIMESTEP_S 6
+#define LP8725_BUCK1_EN_M BIT(0)
+#define LP8725_DVS1_M BIT(2)
+#define LP8725_DVS2_M BIT(3)
+#define LP8725_BUCK2_EN_M BIT(4)
+#define LP8725_BUCK_CL_M 0xC0 /* Addr 09h, 0Bh */
+#define LP8725_BUCK_CL_S 6
+#define LP8725_BUCK1_FPWM_S 1 /* Addr 0Ch */
+#define LP8725_BUCK1_FPWM_M BIT(1)
+#define LP8725_BUCK2_FPWM_S 5
+#define LP8725_BUCK2_FPWM_M BIT(5)
+#define LP8725_EN_LILO1_M BIT(5) /* Addr 0Dh */
+#define LP8725_EN_LILO2_M BIT(6)
+
+/* PWM mode */
+#define LP872X_FORCE_PWM 1
+#define LP872X_AUTO_PWM 0
+
+#define LP8720_NUM_REGULATORS 6
+#define LP8725_NUM_REGULATORS 9
+#define EXTERN_DVS_USED 0
+#define MAX_DELAY 6
+
+/* dump registers in regmap-debugfs */
+#define MAX_REGISTERS 0x0F
+
+enum lp872x_id {
+ LP8720,
+ LP8725,
+};
+
+struct lp872x {
+ struct regmap *regmap;
+ struct device *dev;
+ enum lp872x_id chipid;
+ struct lp872x_platform_data *pdata;
+ struct regulator_dev **regulators;
+ int num_regulators;
+ enum lp872x_dvs_state dvs_pin;
+ int dvs_gpio;
+};
+
+/* LP8720/LP8725 shared voltage table for LDOs */
+static const unsigned int lp872x_ldo_vtbl[] = {
+ 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+ 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 2000000,
+ 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2650000, 2700000,
+ 2750000, 2800000, 2850000, 2900000, 2950000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 LDO4 voltage table */
+static const unsigned int lp8720_ldo4_vtbl[] = {
+ 800000, 850000, 900000, 1000000, 1100000, 1200000, 1250000, 1300000,
+ 1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000,
+ 1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+ 2400000, 2500000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000,
+};
+
+/* LP8725 LILO(Low Input Low Output) voltage table */
+static const unsigned int lp8725_lilo_vtbl[] = {
+ 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
+ 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 BUCK voltage table */
+#define EXT_R 0 /* external resistor divider */
+static const unsigned int lp8720_buck_vtbl[] = {
+ EXT_R, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
+ 1950000, 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000,
+};
+
+/* LP8725 BUCK voltage table */
+static const unsigned int lp8725_buck_vtbl[] = {
+ 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
+ 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+ 1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+ 2400000, 2500000, 2600000, 2700000, 2800000, 2850000, 2900000, 3000000,
+};
+
+/* LP8725 BUCK current limit */
+static const unsigned int lp8725_buck_uA[] = {
+ 460000, 780000, 1050000, 1370000,
+};
+
+static int lp872x_read_byte(struct lp872x *lp, u8 addr, u8 *data)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(lp->regmap, addr, &val);
+ if (ret < 0) {
+ dev_err(lp->dev, "failed to read 0x%.2x\n", addr);
+ return ret;
+ }
+
+ *data = (u8)val;
+ return 0;
+}
+
+static inline int lp872x_write_byte(struct lp872x *lp, u8 addr, u8 data)
+{
+ return regmap_write(lp->regmap, addr, data);
+}
+
+static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
+ unsigned int mask, u8 data)
+{
+ return regmap_update_bits(lp->regmap, addr, mask, data);
+}
+
+static int _rdev_to_offset(struct regulator_dev *rdev)
+{
+ enum lp872x_regulator_id id = rdev_get_id(rdev);
+
+ switch (id) {
+ case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+ return id;
+ case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
+ return id - LP8725_ID_BASE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lp872x_get_timestep_usec(struct lp872x *lp)
+{
+ enum lp872x_id chip = lp->chipid;
+ u8 val, mask, shift;
+ int *time_usec, size, ret;
+ int lp8720_time_usec[] = { 25, 50 };
+ int lp8725_time_usec[] = { 32, 64, 128, 256 };
+
+ switch (chip) {
+ case LP8720:
+ mask = LP8720_TIMESTEP_M;
+ shift = LP8720_TIMESTEP_S;
+ time_usec = &lp8720_time_usec[0];
+ size = ARRAY_SIZE(lp8720_time_usec);
+ break;
+ case LP8725:
+ mask = LP8725_TIMESTEP_M;
+ shift = LP8725_TIMESTEP_S;
+ time_usec = &lp8725_time_usec[0];
+ size = ARRAY_SIZE(lp8725_time_usec);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+ if (ret)
+ return -EINVAL;
+
+ val = (val & mask) >> shift;
+ if (val >= size)
+ return -EINVAL;
+
+ return *(time_usec + val);
+}
+
+static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+ int time_step_us = lp872x_get_timestep_usec(lp);
+ int ret, offset;
+ u8 addr, val;
+
+ if (time_step_us < 0)
+ return -EINVAL;
+
+ switch (regulator) {
+ case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
+ case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
+ offset = _rdev_to_offset(rdev);
+ if (offset < 0)
+ return -EINVAL;
+
+ addr = LP872X_LDO1_VOUT + offset;
+ break;
+ case LP8720_ID_BUCK:
+ addr = LP8720_BUCK_VOUT1;
+ break;
+ case LP8725_ID_BUCK1:
+ addr = LP8725_BUCK1_VOUT1;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = LP8725_BUCK2_VOUT1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = lp872x_read_byte(lp, addr, &val);
+ if (ret)
+ return ret;
+
+ val = (val & LP872X_START_DELAY_M) >> LP872X_START_DELAY_S;
+
+ return val > MAX_DELAY ? 0 : val * time_step_us;
+}
+
+static void lp872x_set_dvs(struct lp872x *lp, int gpio)
+{
+ enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel;
+ enum lp872x_dvs_state state;
+
+ state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW;
+ gpio_set_value(gpio, state);
+ lp->dvs_pin = state;
+}
+
+static u8 lp872x_select_buck_vout_addr(struct lp872x *lp,
+ enum lp872x_regulator_id buck)
+{
+ u8 val, addr;
+
+ if (lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val))
+ return 0;
+
+ switch (buck) {
+ case LP8720_ID_BUCK:
+ if (val & LP8720_EXT_DVS_M) {
+ addr = (lp->dvs_pin == DVS_HIGH) ?
+ LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+ } else {
+ if (lp872x_read_byte(lp, LP8720_ENABLE, &val))
+ return 0;
+
+ addr = val & LP8720_DVS_SEL_M ?
+ LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+ }
+ break;
+ case LP8725_ID_BUCK1:
+ if (val & LP8725_DVS1_M)
+ addr = LP8725_BUCK1_VOUT1;
+ else
+ addr = (lp->dvs_pin == DVS_HIGH) ?
+ LP8725_BUCK1_VOUT1 : LP8725_BUCK1_VOUT2;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = val & LP8725_DVS2_M ?
+ LP8725_BUCK2_VOUT1 : LP8725_BUCK2_VOUT2;
+ break;
+ default:
+ return 0;
+ }
+
+ return addr;
+}
+
+static bool lp872x_is_valid_buck_addr(u8 addr)
+{
+ switch (addr) {
+ case LP8720_BUCK_VOUT1:
+ case LP8720_BUCK_VOUT2:
+ case LP8725_BUCK1_VOUT1:
+ case LP8725_BUCK1_VOUT2:
+ case LP8725_BUCK2_VOUT1:
+ case LP8725_BUCK2_VOUT2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ u8 addr, mask = LP872X_VOUT_M;
+ struct lp872x_dvs *dvs = lp->pdata->dvs;
+
+ if (dvs && gpio_is_valid(dvs->gpio))
+ lp872x_set_dvs(lp, dvs->gpio);
+
+ addr = lp872x_select_buck_vout_addr(lp, buck);
+ if (!lp872x_is_valid_buck_addr(addr))
+ return -EINVAL;
+
+ return lp872x_update_bits(lp, addr, mask, selector);
+}
+
+static int lp872x_buck_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ u8 addr, val;
+ int ret;
+
+ addr = lp872x_select_buck_vout_addr(lp, buck);
+ if (!lp872x_is_valid_buck_addr(addr))
+ return -EINVAL;
+
+ ret = lp872x_read_byte(lp, addr, &val);
+ if (ret)
+ return ret;
+
+ return val & LP872X_VOUT_M;
+}
+
+static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ int i, max = ARRAY_SIZE(lp8725_buck_uA);
+ u8 addr, val;
+
+ switch (buck) {
+ case LP8725_ID_BUCK1:
+ addr = LP8725_BUCK1_VOUT2;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = LP8725_BUCK2_VOUT2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0 ; i < max ; i++)
+ if (lp8725_buck_uA[i] >= min_uA &&
+ lp8725_buck_uA[i] <= max_uA)
+ break;
+
+ if (i == max)
+ return -EINVAL;
+
+ val = i << LP8725_BUCK_CL_S;
+
+ return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val);
+}
+
+static int lp8725_buck_get_current_limit(struct regulator_dev *rdev)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ u8 addr, val;
+ int ret;
+
+ switch (buck) {
+ case LP8725_ID_BUCK1:
+ addr = LP8725_BUCK1_VOUT2;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = LP8725_BUCK2_VOUT2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = lp872x_read_byte(lp, addr, &val);
+ if (ret)
+ return ret;
+
+ val = (val & LP8725_BUCK_CL_M) >> LP8725_BUCK_CL_S;
+
+ return (val < ARRAY_SIZE(lp8725_buck_uA)) ?
+ lp8725_buck_uA[val] : -EINVAL;
+}
+
+static int lp872x_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ u8 addr, mask, shift, val;
+
+ switch (buck) {
+ case LP8720_ID_BUCK:
+ addr = LP8720_BUCK_VOUT2;
+ mask = LP8720_BUCK_FPWM_M;
+ shift = LP8720_BUCK_FPWM_S;
+ break;
+ case LP8725_ID_BUCK1:
+ addr = LP8725_BUCK_CTRL;
+ mask = LP8725_BUCK1_FPWM_M;
+ shift = LP8725_BUCK1_FPWM_S;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = LP8725_BUCK_CTRL;
+ mask = LP8725_BUCK2_FPWM_M;
+ shift = LP8725_BUCK2_FPWM_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode == REGULATOR_MODE_FAST)
+ val = LP872X_FORCE_PWM << shift;
+ else if (mode == REGULATOR_MODE_NORMAL)
+ val = LP872X_AUTO_PWM << shift;
+ else
+ return -EINVAL;
+
+ return lp872x_update_bits(lp, addr, mask, val);
+}
+
+static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev)
+{
+ struct lp872x *lp = rdev_get_drvdata(rdev);
+ enum lp872x_regulator_id buck = rdev_get_id(rdev);
+ u8 addr, mask, val;
+ int ret;
+
+ switch (buck) {
+ case LP8720_ID_BUCK:
+ addr = LP8720_BUCK_VOUT2;
+ mask = LP8720_BUCK_FPWM_M;
+ break;
+ case LP8725_ID_BUCK1:
+ addr = LP8725_BUCK_CTRL;
+ mask = LP8725_BUCK1_FPWM_M;
+ break;
+ case LP8725_ID_BUCK2:
+ addr = LP8725_BUCK_CTRL;
+ mask = LP8725_BUCK2_FPWM_M;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = lp872x_read_byte(lp, addr, &val);
+ if (ret)
+ return ret;
+
+ return val & mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops lp872x_ldo_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp872x_regulator_enable_time,
+};
+
+static struct regulator_ops lp8720_buck_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = lp872x_buck_set_voltage_sel,
+ .get_voltage_sel = lp872x_buck_get_voltage_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp872x_regulator_enable_time,
+ .set_mode = lp872x_buck_set_mode,
+ .get_mode = lp872x_buck_get_mode,
+};
+
+static struct regulator_ops lp8725_buck_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = lp872x_buck_set_voltage_sel,
+ .get_voltage_sel = lp872x_buck_get_voltage_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp872x_regulator_enable_time,
+ .set_mode = lp872x_buck_set_mode,
+ .get_mode = lp872x_buck_get_mode,
+ .set_current_limit = lp8725_buck_set_current_limit,
+ .get_current_limit = lp8725_buck_get_current_limit,
+};
+
+static struct regulator_desc lp8720_regulator_desc[] = {
+ {
+ .name = "ldo1",
+ .id = LP8720_ID_LDO1,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO1_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP872X_EN_LDO1_M,
+ },
+ {
+ .name = "ldo2",
+ .id = LP8720_ID_LDO2,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO2_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP872X_EN_LDO2_M,
+ },
+ {
+ .name = "ldo3",
+ .id = LP8720_ID_LDO3,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO3_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP872X_EN_LDO3_M,
+ },
+ {
+ .name = "ldo4",
+ .id = LP8720_ID_LDO4,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl),
+ .volt_table = lp8720_ldo4_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO4_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP872X_EN_LDO4_M,
+ },
+ {
+ .name = "ldo5",
+ .id = LP8720_ID_LDO5,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO5_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP872X_EN_LDO5_M,
+ },
+ {
+ .name = "buck",
+ .id = LP8720_ID_BUCK,
+ .ops = &lp8720_buck_ops,
+ .n_voltages = ARRAY_SIZE(lp8720_buck_vtbl),
+ .volt_table = lp8720_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8720_ENABLE,
+ .enable_mask = LP8720_EN_BUCK_M,
+ },
+};
+
+static struct regulator_desc lp8725_regulator_desc[] = {
+ {
+ .name = "ldo1",
+ .id = LP8725_ID_LDO1,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO1_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP872X_EN_LDO1_M,
+ },
+ {
+ .name = "ldo2",
+ .id = LP8725_ID_LDO2,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO2_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP872X_EN_LDO2_M,
+ },
+ {
+ .name = "ldo3",
+ .id = LP8725_ID_LDO3,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO3_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP872X_EN_LDO3_M,
+ },
+ {
+ .name = "ldo4",
+ .id = LP8725_ID_LDO4,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO4_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP872X_EN_LDO4_M,
+ },
+ {
+ .name = "ldo5",
+ .id = LP8725_ID_LDO5,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+ .volt_table = lp872x_ldo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP872X_LDO5_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP872X_EN_LDO5_M,
+ },
+ {
+ .name = "lilo1",
+ .id = LP8725_ID_LILO1,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+ .volt_table = lp8725_lilo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8725_LILO1_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP8725_EN_LILO1_M,
+ },
+ {
+ .name = "lilo2",
+ .id = LP8725_ID_LILO2,
+ .ops = &lp872x_ldo_ops,
+ .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+ .volt_table = lp8725_lilo_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8725_LILO2_VOUT,
+ .vsel_mask = LP872X_VOUT_M,
+ .enable_reg = LP8725_LDO_CTRL,
+ .enable_mask = LP8725_EN_LILO2_M,
+ },
+ {
+ .name = "buck1",
+ .id = LP8725_ID_BUCK1,
+ .ops = &lp8725_buck_ops,
+ .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+ .volt_table = lp8725_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP872X_GENERAL_CFG,
+ .enable_mask = LP8725_BUCK1_EN_M,
+ },
+ {
+ .name = "buck2",
+ .id = LP8725_ID_BUCK2,
+ .ops = &lp8725_buck_ops,
+ .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+ .volt_table = lp8725_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP872X_GENERAL_CFG,
+ .enable_mask = LP8725_BUCK2_EN_M,
+ },
+};
+
+static int lp872x_check_dvs_validity(struct lp872x *lp)
+{
+ struct lp872x_dvs *dvs = lp->pdata->dvs;
+ u8 val = 0;
+ int ret;
+
+ ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+ if (ret)
+ return ret;
+
+ ret = 0;
+ if (lp->chipid == LP8720) {
+ if (val & LP8720_EXT_DVS_M)
+ ret = dvs ? 0 : -EINVAL;
+ } else {
+ if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED)
+ ret = dvs ? 0 : -EINVAL;
+ }
+
+ return ret;
+}
+
+static int lp872x_init_dvs(struct lp872x *lp)
+{
+ int ret, gpio;
+ struct lp872x_dvs *dvs = lp->pdata->dvs;
+ enum lp872x_dvs_state pinstate;
+
+ ret = lp872x_check_dvs_validity(lp);
+ if (ret) {
+ dev_warn(lp->dev, "invalid dvs data: %d\n", ret);
+ return ret;
+ }
+
+ gpio = dvs->gpio;
+ if (!gpio_is_valid(gpio)) {
+ dev_err(lp->dev, "invalid gpio: %d\n", gpio);
+ return -EINVAL;
+ }
+
+ pinstate = dvs->init_state;
+ ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
+ if (ret) {
+ dev_err(lp->dev, "gpio request err: %d\n", ret);
+ return ret;
+ }
+
+ lp->dvs_pin = pinstate;
+ lp->dvs_gpio = gpio;
+
+ return 0;
+}
+
+static int lp872x_config(struct lp872x *lp)
+{
+ struct lp872x_platform_data *pdata = lp->pdata;
+ int ret;
+
+ if (!pdata->update_config)
+ return 0;
+
+ ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config);
+ if (ret)
+ return ret;
+
+ return lp872x_init_dvs(lp);
+}
+
+static struct regulator_init_data
+*lp872x_find_regulator_init_data(int id, struct lp872x *lp)
+{
+ int i;
+
+ for (i = 0; i < lp->num_regulators; i++) {
+ if (lp->pdata->regulator_data[i].id == id)
+ return lp->pdata->regulator_data[i].init_data;
+ }
+
+ return NULL;
+}
+
+static int lp872x_regulator_register(struct lp872x *lp)
+{
+ struct regulator_desc *desc;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ int i, ret;
+
+ for (i = 0 ; i < lp->num_regulators ; i++) {
+ desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
+ &lp8725_regulator_desc[i];
+
+ cfg.dev = lp->dev;
+ cfg.init_data = lp872x_find_regulator_init_data(desc->id, lp);
+ cfg.driver_data = lp;
+ cfg.regmap = lp->regmap;
+
+ rdev = regulator_register(desc, &cfg);
+ if (IS_ERR(rdev)) {
+ dev_err(lp->dev, "regulator register err");
+ ret = PTR_ERR(rdev);
+ goto err;
+ }
+
+ *(lp->regulators + i) = rdev;
+ }
+
+ return 0;
+err:
+ while (--i >= 0) {
+ rdev = *(lp->regulators + i);
+ regulator_unregister(rdev);
+ }
+ return ret;
+}
+
+static void lp872x_regulator_unregister(struct lp872x *lp)
+{
+ struct regulator_dev *rdev;
+ int i;
+
+ for (i = 0 ; i < lp->num_regulators ; i++) {
+ rdev = *(lp->regulators + i);
+ regulator_unregister(rdev);
+ }
+}
+
+static const struct regmap_config lp872x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX_REGISTERS,
+};
+
+static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+ struct lp872x *lp;
+ struct lp872x_platform_data *pdata = cl->dev.platform_data;
+ int ret, size, num_regulators;
+ const int lp872x_num_regulators[] = {
+ [LP8720] = LP8720_NUM_REGULATORS,
+ [LP8725] = LP8725_NUM_REGULATORS,
+ };
+
+ if (!pdata) {
+ dev_err(&cl->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
+ if (!lp)
+ goto err_mem;
+
+ num_regulators = lp872x_num_regulators[id->driver_data];
+ size = sizeof(struct regulator_dev *) * num_regulators;
+
+ lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL);
+ if (!lp->regulators)
+ goto err_mem;
+
+ lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config);
+ if (IS_ERR(lp->regmap)) {
+ ret = PTR_ERR(lp->regmap);
+ dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
+ goto err_dev;
+ }
+
+ lp->dev = &cl->dev;
+ lp->pdata = pdata;
+ lp->chipid = id->driver_data;
+ lp->num_regulators = num_regulators;
+ i2c_set_clientdata(cl, lp);
+
+ ret = lp872x_config(lp);
+ if (ret)
+ goto err_dev;
+
+ return lp872x_regulator_register(lp);
+
+err_mem:
+ return -ENOMEM;
+err_dev:
+ return ret;
+}
+
+static int __devexit lp872x_remove(struct i2c_client *cl)
+{
+ struct lp872x *lp = i2c_get_clientdata(cl);
+
+ lp872x_regulator_unregister(lp);
+ return 0;
+}
+
+static const struct i2c_device_id lp872x_ids[] = {
+ {"lp8720", LP8720},
+ {"lp8725", LP8725},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lp872x_ids);
+
+static struct i2c_driver lp872x_driver = {
+ .driver = {
+ .name = "lp872x",
+ .owner = THIS_MODULE,
+ },
+ .probe = lp872x_probe,
+ .remove = __devexit_p(lp872x_remove),
+ .id_table = lp872x_ids,
+};
+
+module_i2c_driver(lp872x_driver);
+
+MODULE_DESCRIPTION("TI/National Semiconductor LP872x PMU Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * TI LP8788 MFD - buck regulator driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * 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/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/lp8788.h>
+#include <linux/gpio.h>
+
+/* register address */
+#define LP8788_EN_BUCK 0x0C
+#define LP8788_BUCK_DVS_SEL 0x1D
+#define LP8788_BUCK1_VOUT0 0x1E
+#define LP8788_BUCK1_VOUT1 0x1F
+#define LP8788_BUCK1_VOUT2 0x20
+#define LP8788_BUCK1_VOUT3 0x21
+#define LP8788_BUCK2_VOUT0 0x22
+#define LP8788_BUCK2_VOUT1 0x23
+#define LP8788_BUCK2_VOUT2 0x24
+#define LP8788_BUCK2_VOUT3 0x25
+#define LP8788_BUCK3_VOUT 0x26
+#define LP8788_BUCK4_VOUT 0x27
+#define LP8788_BUCK1_TIMESTEP 0x28
+#define LP8788_BUCK_PWM 0x2D
+
+/* mask/shift bits */
+#define LP8788_EN_BUCK1_M BIT(0) /* Addr 0Ch */
+#define LP8788_EN_BUCK2_M BIT(1)
+#define LP8788_EN_BUCK3_M BIT(2)
+#define LP8788_EN_BUCK4_M BIT(3)
+#define LP8788_BUCK1_DVS_SEL_M 0x04 /* Addr 1Dh */
+#define LP8788_BUCK1_DVS_M 0x03
+#define LP8788_BUCK1_DVS_S 0
+#define LP8788_BUCK2_DVS_SEL_M 0x40
+#define LP8788_BUCK2_DVS_M 0x30
+#define LP8788_BUCK2_DVS_S 4
+#define LP8788_BUCK1_DVS_I2C BIT(2)
+#define LP8788_BUCK2_DVS_I2C BIT(6)
+#define LP8788_BUCK1_DVS_PIN (0 << 2)
+#define LP8788_BUCK2_DVS_PIN (0 << 6)
+#define LP8788_VOUT_M 0x1F /* Addr 1Eh ~ 27h */
+#define LP8788_STARTUP_TIME_M 0xF8 /* Addr 28h ~ 2Bh */
+#define LP8788_STARTUP_TIME_S 3
+#define LP8788_FPWM_BUCK1_M BIT(0) /* Addr 2Dh */
+#define LP8788_FPWM_BUCK1_S 0
+#define LP8788_FPWM_BUCK2_M BIT(1)
+#define LP8788_FPWM_BUCK2_S 1
+#define LP8788_FPWM_BUCK3_M BIT(2)
+#define LP8788_FPWM_BUCK3_S 2
+#define LP8788_FPWM_BUCK4_M BIT(3)
+#define LP8788_FPWM_BUCK4_S 3
+
+#define INVALID_ADDR 0xFF
+#define LP8788_FORCE_PWM 1
+#define LP8788_AUTO_PWM 0
+#define PIN_LOW 0
+#define PIN_HIGH 1
+#define ENABLE_TIME_USEC 32
+
+enum lp8788_dvs_state {
+ DVS_LOW = GPIOF_OUT_INIT_LOW,
+ DVS_HIGH = GPIOF_OUT_INIT_HIGH,
+};
+
+enum lp8788_dvs_mode {
+ REGISTER,
+ EXTPIN,
+};
+
+enum lp8788_buck_id {
+ BUCK1,
+ BUCK2,
+ BUCK3,
+ BUCK4,
+};
+
+struct lp8788_pwm_map {
+ u8 mask;
+ u8 shift;
+};
+
+struct lp8788_buck {
+ struct lp8788 *lp;
+ struct regulator_dev *regulator;
+ struct lp8788_pwm_map *pmap;
+ void *dvs;
+};
+
+/* BUCK 1 ~ 4 voltage table */
+static const int lp8788_buck_vtbl[] = {
+ 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
+ 1950000, 2000000,
+};
+
+/* buck pwm mode selection : used for set/get_mode in regulator ops
+ * @forced pwm : fast mode
+ * @auto pwm : normal mode
+ */
+static struct lp8788_pwm_map buck_pmap[] = {
+ [BUCK1] = {
+ .mask = LP8788_FPWM_BUCK1_M,
+ .shift = LP8788_FPWM_BUCK1_S,
+ },
+ [BUCK2] = {
+ .mask = LP8788_FPWM_BUCK2_M,
+ .shift = LP8788_FPWM_BUCK2_S,
+ },
+ [BUCK3] = {
+ .mask = LP8788_FPWM_BUCK3_M,
+ .shift = LP8788_FPWM_BUCK3_S,
+ },
+ [BUCK4] = {
+ .mask = LP8788_FPWM_BUCK4_M,
+ .shift = LP8788_FPWM_BUCK4_S,
+ },
+};
+
+static const u8 buck1_vout_addr[] = {
+ LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
+ LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
+};
+
+static const u8 buck2_vout_addr[] = {
+ LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
+ LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
+};
+
+static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
+{
+ struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
+ enum lp8788_dvs_state pinstate;
+
+ if (!dvs)
+ return;
+
+ pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
+ if (gpio_is_valid(dvs->gpio))
+ gpio_set_value(dvs->gpio, pinstate);
+}
+
+static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
+{
+ struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
+ enum lp8788_dvs_state pin1, pin2;
+
+ if (!dvs)
+ return;
+
+ switch (dvs->vsel) {
+ case DVS_SEL_V0:
+ pin1 = DVS_LOW;
+ pin2 = DVS_LOW;
+ break;
+ case DVS_SEL_V1:
+ pin1 = DVS_HIGH;
+ pin2 = DVS_LOW;
+ break;
+ case DVS_SEL_V2:
+ pin1 = DVS_LOW;
+ pin2 = DVS_HIGH;
+ break;
+ case DVS_SEL_V3:
+ pin1 = DVS_HIGH;
+ pin2 = DVS_HIGH;
+ break;
+ default:
+ return;
+ }
+
+ if (gpio_is_valid(dvs->gpio[0]))
+ gpio_set_value(dvs->gpio[0], pin1);
+
+ if (gpio_is_valid(dvs->gpio[1]))
+ gpio_set_value(dvs->gpio[1], pin2);
+}
+
+static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+ switch (id) {
+ case BUCK1:
+ lp8788_buck1_set_dvs(buck);
+ break;
+ case BUCK2:
+ lp8788_buck2_set_dvs(buck);
+ break;
+ default:
+ break;
+ }
+}
+
+static enum lp8788_dvs_mode
+lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+ u8 val, mask;
+
+ switch (id) {
+ case BUCK1:
+ mask = LP8788_BUCK1_DVS_SEL_M;
+ break;
+ case BUCK2:
+ mask = LP8788_BUCK2_DVS_SEL_M;
+ break;
+ default:
+ return REGISTER;
+ }
+
+ lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+
+ return val & mask ? REGISTER : EXTPIN;
+}
+
+static bool lp8788_is_valid_buck_addr(u8 addr)
+{
+ switch (addr) {
+ case LP8788_BUCK1_VOUT0:
+ case LP8788_BUCK1_VOUT1:
+ case LP8788_BUCK1_VOUT2:
+ case LP8788_BUCK1_VOUT3:
+ case LP8788_BUCK2_VOUT0:
+ case LP8788_BUCK2_VOUT1:
+ case LP8788_BUCK2_VOUT2:
+ case LP8788_BUCK2_VOUT3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
+ enum lp8788_buck_id id)
+{
+ enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
+ struct lp8788_buck1_dvs *b1_dvs;
+ struct lp8788_buck2_dvs *b2_dvs;
+ u8 val, idx, addr;
+ int pin1, pin2;
+
+ switch (id) {
+ case BUCK1:
+ if (mode == EXTPIN) {
+ b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
+ if (!b1_dvs)
+ goto err;
+
+ idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
+ } else {
+ lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+ idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
+ }
+ addr = buck1_vout_addr[idx];
+ break;
+ case BUCK2:
+ if (mode == EXTPIN) {
+ b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
+ if (!b2_dvs)
+ goto err;
+
+ pin1 = gpio_get_value(b2_dvs->gpio[0]);
+ pin2 = gpio_get_value(b2_dvs->gpio[1]);
+
+ if (pin1 == PIN_LOW && pin2 == PIN_LOW)
+ idx = 0;
+ else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
+ idx = 2;
+ else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
+ idx = 1;
+ else
+ idx = 3;
+ } else {
+ lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+ idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
+ }
+ addr = buck2_vout_addr[idx];
+ break;
+ default:
+ goto err;
+ }
+
+ return addr;
+err:
+ return INVALID_ADDR;
+}
+
+static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+ enum lp8788_buck_id id = rdev_get_id(rdev);
+ u8 addr;
+
+ if (buck->dvs)
+ lp8788_set_dvs(buck, id);
+
+ addr = lp8788_select_buck_vout_addr(buck, id);
+ if (!lp8788_is_valid_buck_addr(addr))
+ return -EINVAL;
+
+ return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
+}
+
+static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+ enum lp8788_buck_id id = rdev_get_id(rdev);
+ int ret;
+ u8 val, addr;
+
+ addr = lp8788_select_buck_vout_addr(buck, id);
+ if (!lp8788_is_valid_buck_addr(addr))
+ return -EINVAL;
+
+ ret = lp8788_read_byte(buck->lp, addr, &val);
+ if (ret)
+ return ret;
+
+ return val & LP8788_VOUT_M;
+}
+
+static int lp8788_buck_enable_time(struct regulator_dev *rdev)
+{
+ struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+ enum lp8788_buck_id id = rdev_get_id(rdev);
+ u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
+
+ if (lp8788_read_byte(buck->lp, addr, &val))
+ return -EINVAL;
+
+ val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
+
+ return ENABLE_TIME_USEC * val;
+}
+
+static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+ struct lp8788_pwm_map *pmap = buck->pmap;
+ u8 val;
+
+ if (!pmap)
+ return -EINVAL;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = LP8788_FORCE_PWM << pmap->shift;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = LP8788_AUTO_PWM << pmap->shift;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val);
+}
+
+static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
+{
+ struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+ struct lp8788_pwm_map *pmap = buck->pmap;
+ u8 val;
+ int ret;
+
+ if (!pmap)
+ return -EINVAL;
+
+ ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
+ if (ret)
+ return ret;
+
+ return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops lp8788_buck12_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = lp8788_buck12_set_voltage_sel,
+ .get_voltage_sel = lp8788_buck12_get_voltage_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp8788_buck_enable_time,
+ .set_mode = lp8788_buck_set_mode,
+ .get_mode = lp8788_buck_get_mode,
+};
+
+static struct regulator_ops lp8788_buck34_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp8788_buck_enable_time,
+ .set_mode = lp8788_buck_set_mode,
+ .get_mode = lp8788_buck_get_mode,
+};
+
+static struct regulator_desc lp8788_buck_desc[] = {
+ {
+ .name = "buck1",
+ .id = BUCK1,
+ .ops = &lp8788_buck12_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+ .volt_table = lp8788_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_BUCK,
+ .enable_mask = LP8788_EN_BUCK1_M,
+ },
+ {
+ .name = "buck2",
+ .id = BUCK2,
+ .ops = &lp8788_buck12_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+ .volt_table = lp8788_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_BUCK,
+ .enable_mask = LP8788_EN_BUCK2_M,
+ },
+ {
+ .name = "buck3",
+ .id = BUCK3,
+ .ops = &lp8788_buck34_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+ .volt_table = lp8788_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_BUCK3_VOUT,
+ .vsel_mask = LP8788_VOUT_M,
+ .enable_reg = LP8788_EN_BUCK,
+ .enable_mask = LP8788_EN_BUCK3_M,
+ },
+ {
+ .name = "buck4",
+ .id = BUCK4,
+ .ops = &lp8788_buck34_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+ .volt_table = lp8788_buck_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_BUCK4_VOUT,
+ .vsel_mask = LP8788_VOUT_M,
+ .enable_reg = LP8788_EN_BUCK,
+ .enable_mask = LP8788_EN_BUCK4_M,
+ },
+};
+
+static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp,
+ enum lp8788_buck_id id)
+{
+ u8 mask, val;
+
+ switch (id) {
+ case BUCK1:
+ mask = LP8788_BUCK1_DVS_SEL_M;
+ val = LP8788_BUCK1_DVS_I2C;
+ break;
+ case BUCK2:
+ mask = LP8788_BUCK2_DVS_SEL_M;
+ val = LP8788_BUCK2_DVS_I2C;
+ break;
+ default:
+ return 0;
+ }
+
+ return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val);
+}
+
+static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name)
+{
+ struct device *dev = buck->lp->dev;
+
+ if (!gpio_is_valid(gpio)) {
+ dev_err(dev, "invalid gpio: %d\n", gpio);
+ return -EINVAL;
+ }
+
+ return devm_gpio_request_one(dev, gpio, DVS_LOW, name);
+}
+
+static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
+ enum lp8788_buck_id id)
+{
+ struct lp8788_platform_data *pdata = buck->lp->pdata;
+ char *b1_name = "LP8788_B1_DVS";
+ char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
+ int i, gpio, ret;
+
+ switch (id) {
+ case BUCK1:
+ gpio = pdata->buck1_dvs->gpio;
+ ret = _gpio_request(buck, gpio, b1_name);
+ if (ret)
+ return ret;
+
+ buck->dvs = pdata->buck1_dvs;
+ break;
+ case BUCK2:
+ for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
+ gpio = pdata->buck2_dvs->gpio[i];
+ ret = _gpio_request(buck, gpio, b2_name[i]);
+ if (ret)
+ return ret;
+ }
+ buck->dvs = pdata->buck2_dvs;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+ struct lp8788_platform_data *pdata = buck->lp->pdata;
+ u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
+ u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
+
+ /* no dvs for buck3, 4 */
+ if (id == BUCK3 || id == BUCK4)
+ return 0;
+
+ /* no dvs platform data, then dvs will be selected by I2C registers */
+ if (!pdata)
+ goto set_default_dvs_mode;
+
+ if ((id == BUCK1 && !pdata->buck1_dvs) ||
+ (id == BUCK2 && !pdata->buck2_dvs))
+ goto set_default_dvs_mode;
+
+ if (lp8788_dvs_gpio_request(buck, id))
+ goto set_default_dvs_mode;
+
+ return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
+ val[id]);
+
+set_default_dvs_mode:
+ return lp8788_set_default_dvs_ctrl_mode(buck->lp, id);
+}
+
+static __devinit int lp8788_buck_probe(struct platform_device *pdev)
+{
+ struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+ int id = pdev->id;
+ struct lp8788_buck *buck;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ int ret;
+
+ buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
+ if (!buck)
+ return -ENOMEM;
+
+ buck->lp = lp;
+ buck->pmap = &buck_pmap[id];
+
+ ret = lp8788_init_dvs(buck, id);
+ if (ret)
+ return ret;
+
+ cfg.dev = lp->dev;
+ cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
+ cfg.driver_data = buck;
+ cfg.regmap = lp->regmap;
+
+ rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
+ id + 1, ret);
+ return ret;
+ }
+
+ buck->regulator = rdev;
+ platform_set_drvdata(pdev, buck);
+
+ return 0;
+}
+
+static int __devexit lp8788_buck_remove(struct platform_device *pdev)
+{
+ struct lp8788_buck *buck = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ regulator_unregister(buck->regulator);
+
+ return 0;
+}
+
+static struct platform_driver lp8788_buck_driver = {
+ .probe = lp8788_buck_probe,
+ .remove = __devexit_p(lp8788_buck_remove),
+ .driver = {
+ .name = LP8788_DEV_BUCK,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lp8788_buck_init(void)
+{
+ return platform_driver_register(&lp8788_buck_driver);
+}
+subsys_initcall(lp8788_buck_init);
+
+static void __exit lp8788_buck_exit(void)
+{
+ platform_driver_unregister(&lp8788_buck_driver);
+}
+module_exit(lp8788_buck_exit);
+
+MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-buck");
--- /dev/null
+/*
+ * TI LP8788 MFD - ldo regulator driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * 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/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/gpio.h>
+#include <linux/mfd/lp8788.h>
+
+/* register address */
+#define LP8788_EN_LDO_A 0x0D /* DLDO 1 ~ 8 */
+#define LP8788_EN_LDO_B 0x0E /* DLDO 9 ~ 12, ALDO 1 ~ 4 */
+#define LP8788_EN_LDO_C 0x0F /* ALDO 5 ~ 10 */
+#define LP8788_EN_SEL 0x10
+#define LP8788_DLDO1_VOUT 0x2E
+#define LP8788_DLDO2_VOUT 0x2F
+#define LP8788_DLDO3_VOUT 0x30
+#define LP8788_DLDO4_VOUT 0x31
+#define LP8788_DLDO5_VOUT 0x32
+#define LP8788_DLDO6_VOUT 0x33
+#define LP8788_DLDO7_VOUT 0x34
+#define LP8788_DLDO8_VOUT 0x35
+#define LP8788_DLDO9_VOUT 0x36
+#define LP8788_DLDO10_VOUT 0x37
+#define LP8788_DLDO11_VOUT 0x38
+#define LP8788_DLDO12_VOUT 0x39
+#define LP8788_ALDO1_VOUT 0x3A
+#define LP8788_ALDO2_VOUT 0x3B
+#define LP8788_ALDO3_VOUT 0x3C
+#define LP8788_ALDO4_VOUT 0x3D
+#define LP8788_ALDO5_VOUT 0x3E
+#define LP8788_ALDO6_VOUT 0x3F
+#define LP8788_ALDO7_VOUT 0x40
+#define LP8788_ALDO8_VOUT 0x41
+#define LP8788_ALDO9_VOUT 0x42
+#define LP8788_ALDO10_VOUT 0x43
+#define LP8788_DLDO1_TIMESTEP 0x44
+
+/* mask/shift bits */
+#define LP8788_EN_DLDO1_M BIT(0) /* Addr 0Dh ~ 0Fh */
+#define LP8788_EN_DLDO2_M BIT(1)
+#define LP8788_EN_DLDO3_M BIT(2)
+#define LP8788_EN_DLDO4_M BIT(3)
+#define LP8788_EN_DLDO5_M BIT(4)
+#define LP8788_EN_DLDO6_M BIT(5)
+#define LP8788_EN_DLDO7_M BIT(6)
+#define LP8788_EN_DLDO8_M BIT(7)
+#define LP8788_EN_DLDO9_M BIT(0)
+#define LP8788_EN_DLDO10_M BIT(1)
+#define LP8788_EN_DLDO11_M BIT(2)
+#define LP8788_EN_DLDO12_M BIT(3)
+#define LP8788_EN_ALDO1_M BIT(4)
+#define LP8788_EN_ALDO2_M BIT(5)
+#define LP8788_EN_ALDO3_M BIT(6)
+#define LP8788_EN_ALDO4_M BIT(7)
+#define LP8788_EN_ALDO5_M BIT(0)
+#define LP8788_EN_ALDO6_M BIT(1)
+#define LP8788_EN_ALDO7_M BIT(2)
+#define LP8788_EN_ALDO8_M BIT(3)
+#define LP8788_EN_ALDO9_M BIT(4)
+#define LP8788_EN_ALDO10_M BIT(5)
+#define LP8788_EN_SEL_DLDO911_M BIT(0) /* Addr 10h */
+#define LP8788_EN_SEL_DLDO7_M BIT(1)
+#define LP8788_EN_SEL_ALDO7_M BIT(2)
+#define LP8788_EN_SEL_ALDO5_M BIT(3)
+#define LP8788_EN_SEL_ALDO234_M BIT(4)
+#define LP8788_EN_SEL_ALDO1_M BIT(5)
+#define LP8788_VOUT_5BIT_M 0x1F /* Addr 2Eh ~ 43h */
+#define LP8788_VOUT_4BIT_M 0x0F
+#define LP8788_VOUT_3BIT_M 0x07
+#define LP8788_VOUT_1BIT_M 0x01
+#define LP8788_STARTUP_TIME_M 0xF8 /* Addr 44h ~ 59h */
+#define LP8788_STARTUP_TIME_S 3
+
+#define ENABLE_TIME_USEC 32
+#define ENABLE GPIOF_OUT_INIT_HIGH
+#define DISABLE GPIOF_OUT_INIT_LOW
+
+enum lp8788_enable_mode {
+ REGISTER,
+ EXTPIN,
+};
+
+enum lp8788_ldo_id {
+ DLDO1,
+ DLDO2,
+ DLDO3,
+ DLDO4,
+ DLDO5,
+ DLDO6,
+ DLDO7,
+ DLDO8,
+ DLDO9,
+ DLDO10,
+ DLDO11,
+ DLDO12,
+ ALDO1,
+ ALDO2,
+ ALDO3,
+ ALDO4,
+ ALDO5,
+ ALDO6,
+ ALDO7,
+ ALDO8,
+ ALDO9,
+ ALDO10,
+};
+
+struct lp8788_ldo {
+ struct lp8788 *lp;
+ struct regulator_desc *desc;
+ struct regulator_dev *regulator;
+ struct lp8788_ldo_enable_pin *en_pin;
+};
+
+/* DLDO 1, 2, 3, 9 voltage table */
+const int lp8788_dldo1239_vtbl[] = {
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000,
+ 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000,
+ 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000,
+};
+
+/* DLDO 4 voltage table */
+static const int lp8788_dldo4_vtbl[] = { 1800000, 3000000 };
+
+/* DLDO 5, 7, 8 and ALDO 6 voltage table */
+static const int lp8788_dldo578_aldo6_vtbl[] = {
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3000000, 3000000, 3000000,
+};
+
+/* DLDO 6 voltage table */
+static const int lp8788_dldo6_vtbl[] = {
+ 3000000, 3100000, 3200000, 3300000, 3400000, 3500000, 3600000, 3600000,
+};
+
+/* DLDO 10, 11 voltage table */
+static const int lp8788_dldo1011_vtbl[] = {
+ 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000,
+ 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000,
+};
+
+/* ALDO 1 voltage table */
+static const int lp8788_aldo1_vtbl[] = { 1800000, 2850000 };
+
+/* ALDO 7 voltage table */
+static const int lp8788_aldo7_vtbl[] = {
+ 1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000,
+};
+
+static enum lp8788_ldo_id lp8788_dldo_id[] = {
+ DLDO1,
+ DLDO2,
+ DLDO3,
+ DLDO4,
+ DLDO5,
+ DLDO6,
+ DLDO7,
+ DLDO8,
+ DLDO9,
+ DLDO10,
+ DLDO11,
+ DLDO12,
+};
+
+static enum lp8788_ldo_id lp8788_aldo_id[] = {
+ ALDO1,
+ ALDO2,
+ ALDO3,
+ ALDO4,
+ ALDO5,
+ ALDO6,
+ ALDO7,
+ ALDO8,
+ ALDO9,
+ ALDO10,
+};
+
+/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
+ : can be enabled either by external pin or by i2c register */
+static enum lp8788_enable_mode
+lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
+{
+ int ret;
+ u8 val, mask;
+
+ ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
+ if (ret)
+ return ret;
+
+ switch (id) {
+ case DLDO7:
+ mask = LP8788_EN_SEL_DLDO7_M;
+ break;
+ case DLDO9:
+ case DLDO11:
+ mask = LP8788_EN_SEL_DLDO911_M;
+ break;
+ case ALDO1:
+ mask = LP8788_EN_SEL_ALDO1_M;
+ break;
+ case ALDO2 ... ALDO4:
+ mask = LP8788_EN_SEL_ALDO234_M;
+ break;
+ case ALDO5:
+ mask = LP8788_EN_SEL_ALDO5_M;
+ break;
+ case ALDO7:
+ mask = LP8788_EN_SEL_ALDO7_M;
+ break;
+ default:
+ return REGISTER;
+ }
+
+ return val & mask ? EXTPIN : REGISTER;
+}
+
+static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
+{
+ struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+
+ if (!pin)
+ return -EINVAL;
+
+ if (gpio_is_valid(pin->gpio))
+ gpio_set_value(pin->gpio, pinstate);
+
+ return 0;
+}
+
+static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
+{
+ struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+
+ if (!pin)
+ return -EINVAL;
+
+ return gpio_get_value(pin->gpio) ? 1 : 0;
+}
+
+static int lp8788_ldo_enable(struct regulator_dev *rdev)
+{
+ struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+ enum lp8788_ldo_id id = rdev_get_id(rdev);
+ enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+ switch (mode) {
+ case EXTPIN:
+ return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
+ case REGISTER:
+ return regulator_enable_regmap(rdev);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lp8788_ldo_disable(struct regulator_dev *rdev)
+{
+ struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+ enum lp8788_ldo_id id = rdev_get_id(rdev);
+ enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+ switch (mode) {
+ case EXTPIN:
+ return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
+ case REGISTER:
+ return regulator_disable_regmap(rdev);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+ enum lp8788_ldo_id id = rdev_get_id(rdev);
+ enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+ switch (mode) {
+ case EXTPIN:
+ return lp8788_ldo_is_enabled_by_extern_pin(ldo);
+ case REGISTER:
+ return regulator_is_enabled_regmap(rdev);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
+{
+ struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+ enum lp8788_ldo_id id = rdev_get_id(rdev);
+ u8 val, addr = LP8788_DLDO1_TIMESTEP + id;
+
+ if (lp8788_read_byte(ldo->lp, addr, &val))
+ return -EINVAL;
+
+ val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
+
+ return ENABLE_TIME_USEC * val;
+}
+
+static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev)
+{
+ enum lp8788_ldo_id id = rdev_get_id(rdev);
+
+ switch (id) {
+ case ALDO2 ... ALDO5:
+ return 2850000;
+ case DLDO12:
+ case ALDO8 ... ALDO9:
+ return 2500000;
+ case ALDO10:
+ return 1100000;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct regulator_ops lp8788_ldo_voltage_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = lp8788_ldo_enable,
+ .disable = lp8788_ldo_disable,
+ .is_enabled = lp8788_ldo_is_enabled,
+ .enable_time = lp8788_ldo_enable_time,
+};
+
+static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
+ .get_voltage = lp8788_ldo_fixed_get_voltage,
+ .enable = lp8788_ldo_enable,
+ .disable = lp8788_ldo_disable,
+ .is_enabled = lp8788_ldo_is_enabled,
+ .enable_time = lp8788_ldo_enable_time,
+};
+
+static struct regulator_desc lp8788_dldo_desc[] = {
+ {
+ .name = "dldo1",
+ .id = DLDO1,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+ .volt_table = lp8788_dldo1239_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO1_VOUT,
+ .vsel_mask = LP8788_VOUT_5BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO1_M,
+ },
+ {
+ .name = "dldo2",
+ .id = DLDO2,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+ .volt_table = lp8788_dldo1239_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO2_VOUT,
+ .vsel_mask = LP8788_VOUT_5BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO2_M,
+ },
+ {
+ .name = "dldo3",
+ .id = DLDO3,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+ .volt_table = lp8788_dldo1239_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO3_VOUT,
+ .vsel_mask = LP8788_VOUT_5BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO3_M,
+ },
+ {
+ .name = "dldo4",
+ .id = DLDO4,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo4_vtbl),
+ .volt_table = lp8788_dldo4_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO4_VOUT,
+ .vsel_mask = LP8788_VOUT_1BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO4_M,
+ },
+ {
+ .name = "dldo5",
+ .id = DLDO5,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+ .volt_table = lp8788_dldo578_aldo6_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO5_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO5_M,
+ },
+ {
+ .name = "dldo6",
+ .id = DLDO6,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo6_vtbl),
+ .volt_table = lp8788_dldo6_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO6_VOUT,
+ .vsel_mask = LP8788_VOUT_3BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO6_M,
+ },
+ {
+ .name = "dldo7",
+ .id = DLDO7,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+ .volt_table = lp8788_dldo578_aldo6_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO7_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO7_M,
+ },
+ {
+ .name = "dldo8",
+ .id = DLDO8,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+ .volt_table = lp8788_dldo578_aldo6_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO8_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_A,
+ .enable_mask = LP8788_EN_DLDO8_M,
+ },
+ {
+ .name = "dldo9",
+ .id = DLDO9,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+ .volt_table = lp8788_dldo1239_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO9_VOUT,
+ .vsel_mask = LP8788_VOUT_5BIT_M,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_DLDO9_M,
+ },
+ {
+ .name = "dldo10",
+ .id = DLDO10,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl),
+ .volt_table = lp8788_dldo1011_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO10_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_DLDO10_M,
+ },
+ {
+ .name = "dldo11",
+ .id = DLDO11,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl),
+ .volt_table = lp8788_dldo1011_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_DLDO11_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_DLDO11_M,
+ },
+ {
+ .name = "dldo12",
+ .id = DLDO12,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_DLDO12_M,
+ },
+};
+
+static struct regulator_desc lp8788_aldo_desc[] = {
+ {
+ .name = "aldo1",
+ .id = ALDO1,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_aldo1_vtbl),
+ .volt_table = lp8788_aldo1_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_ALDO1_VOUT,
+ .vsel_mask = LP8788_VOUT_1BIT_M,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_ALDO1_M,
+ },
+ {
+ .name = "aldo2",
+ .id = ALDO2,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_ALDO2_M,
+ },
+ {
+ .name = "aldo3",
+ .id = ALDO3,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_ALDO3_M,
+ },
+ {
+ .name = "aldo4",
+ .id = ALDO4,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_B,
+ .enable_mask = LP8788_EN_ALDO4_M,
+ },
+ {
+ .name = "aldo5",
+ .id = ALDO5,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO5_M,
+ },
+ {
+ .name = "aldo6",
+ .id = ALDO6,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+ .volt_table = lp8788_dldo578_aldo6_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_ALDO6_VOUT,
+ .vsel_mask = LP8788_VOUT_4BIT_M,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO6_M,
+ },
+ {
+ .name = "aldo7",
+ .id = ALDO7,
+ .ops = &lp8788_ldo_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lp8788_aldo7_vtbl),
+ .volt_table = lp8788_aldo7_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LP8788_ALDO7_VOUT,
+ .vsel_mask = LP8788_VOUT_3BIT_M,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO7_M,
+ },
+ {
+ .name = "aldo8",
+ .id = ALDO8,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO8_M,
+ },
+ {
+ .name = "aldo9",
+ .id = ALDO9,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO9_M,
+ },
+ {
+ .name = "aldo10",
+ .id = ALDO10,
+ .ops = &lp8788_ldo_voltage_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = LP8788_EN_LDO_C,
+ .enable_mask = LP8788_EN_ALDO10_M,
+ },
+};
+
+static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
+ enum lp8788_ext_ldo_en_id id)
+{
+ struct device *dev = ldo->lp->dev;
+ struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+ int ret, gpio, pinstate;
+ char *name[] = {
+ [EN_ALDO1] = "LP8788_EN_ALDO1",
+ [EN_ALDO234] = "LP8788_EN_ALDO234",
+ [EN_ALDO5] = "LP8788_EN_ALDO5",
+ [EN_ALDO7] = "LP8788_EN_ALDO7",
+ [EN_DLDO7] = "LP8788_EN_DLDO7",
+ [EN_DLDO911] = "LP8788_EN_DLDO911",
+ };
+
+ gpio = pin->gpio;
+ if (!gpio_is_valid(gpio)) {
+ dev_err(dev, "invalid gpio: %d\n", gpio);
+ return -EINVAL;
+ }
+
+ pinstate = pin->init_state;
+ ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]);
+ if (ret == -EBUSY) {
+ dev_warn(dev, "gpio%d already used\n", gpio);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
+ enum lp8788_ldo_id id)
+{
+ int ret;
+ struct lp8788 *lp = ldo->lp;
+ struct lp8788_platform_data *pdata = lp->pdata;
+ enum lp8788_ext_ldo_en_id enable_id;
+ u8 en_mask[] = {
+ [EN_ALDO1] = LP8788_EN_SEL_ALDO1_M,
+ [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M,
+ [EN_ALDO5] = LP8788_EN_SEL_ALDO5_M,
+ [EN_ALDO7] = LP8788_EN_SEL_ALDO7_M,
+ [EN_DLDO7] = LP8788_EN_SEL_DLDO7_M,
+ [EN_DLDO911] = LP8788_EN_SEL_DLDO911_M,
+ };
+ u8 val[] = {
+ [EN_ALDO1] = 0 << 5,
+ [EN_ALDO234] = 0 << 4,
+ [EN_ALDO5] = 0 << 3,
+ [EN_ALDO7] = 0 << 2,
+ [EN_DLDO7] = 0 << 1,
+ [EN_DLDO911] = 0 << 0,
+ };
+
+ switch (id) {
+ case DLDO7:
+ enable_id = EN_DLDO7;
+ break;
+ case DLDO9:
+ case DLDO11:
+ enable_id = EN_DLDO911;
+ break;
+ case ALDO1:
+ enable_id = EN_ALDO1;
+ break;
+ case ALDO2 ... ALDO4:
+ enable_id = EN_ALDO234;
+ break;
+ case ALDO5:
+ enable_id = EN_ALDO5;
+ break;
+ case ALDO7:
+ enable_id = EN_ALDO7;
+ break;
+ default:
+ return 0;
+ }
+
+ /* if no platform data for ldo pin, then set default enable mode */
+ if (!pdata || !pdata->ldo_pin || !pdata->ldo_pin[enable_id])
+ goto set_default_ldo_enable_mode;
+
+ ldo->en_pin = pdata->ldo_pin[enable_id];
+
+ ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
+ if (ret)
+ goto set_default_ldo_enable_mode;
+
+ return ret;
+
+set_default_ldo_enable_mode:
+ return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id],
+ val[enable_id]);
+}
+
+static __devinit int lp8788_dldo_probe(struct platform_device *pdev)
+{
+ struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+ int id = pdev->id;
+ struct lp8788_ldo *ldo;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ int ret;
+
+ ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+ if (!ldo)
+ return -ENOMEM;
+
+ ldo->lp = lp;
+ ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
+ if (ret)
+ return ret;
+
+ cfg.dev = lp->dev;
+ cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
+ cfg.driver_data = ldo;
+ cfg.regmap = lp->regmap;
+
+ rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
+ id + 1, ret);
+ return ret;
+ }
+
+ ldo->regulator = rdev;
+ platform_set_drvdata(pdev, ldo);
+
+ return 0;
+}
+
+static int __devexit lp8788_dldo_remove(struct platform_device *pdev)
+{
+ struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ regulator_unregister(ldo->regulator);
+
+ return 0;
+}
+
+static struct platform_driver lp8788_dldo_driver = {
+ .probe = lp8788_dldo_probe,
+ .remove = __devexit_p(lp8788_dldo_remove),
+ .driver = {
+ .name = LP8788_DEV_DLDO,
+ .owner = THIS_MODULE,
+ },
+};
+
+static __devinit int lp8788_aldo_probe(struct platform_device *pdev)
+{
+ struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+ int id = pdev->id;
+ struct lp8788_ldo *ldo;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ int ret;
+
+ ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+ if (!ldo)
+ return -ENOMEM;
+
+ ldo->lp = lp;
+ ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
+ if (ret)
+ return ret;
+
+ cfg.dev = lp->dev;
+ cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
+ cfg.driver_data = ldo;
+ cfg.regmap = lp->regmap;
+
+ rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
+ id + 1, ret);
+ return ret;
+ }
+
+ ldo->regulator = rdev;
+ platform_set_drvdata(pdev, ldo);
+
+ return 0;
+}
+
+static int __devexit lp8788_aldo_remove(struct platform_device *pdev)
+{
+ struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ regulator_unregister(ldo->regulator);
+
+ return 0;
+}
+
+static struct platform_driver lp8788_aldo_driver = {
+ .probe = lp8788_aldo_probe,
+ .remove = __devexit_p(lp8788_aldo_remove),
+ .driver = {
+ .name = LP8788_DEV_ALDO,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lp8788_ldo_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&lp8788_dldo_driver);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&lp8788_aldo_driver);
+}
+subsys_initcall(lp8788_ldo_init);
+
+static void __exit lp8788_ldo_exit(void)
+{
+ platform_driver_unregister(&lp8788_aldo_driver);
+ platform_driver_unregister(&lp8788_dldo_driver);
+}
+module_exit(lp8788_ldo_exit);
+
+MODULE_DESCRIPTION("TI LP8788 LDO Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-dldo");
+MODULE_ALIAS("platform:lp8788-aldo");
struct regulator_dev *rdev[0];
};
+/*
+ * V6 voltage
+ * On I2C bus, sending a "x" byte to the max1586 means :
+ * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
+ * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
+ */
+static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
+
/*
* V3 voltage
* On I2C bus, sending a "x" byte to the max1586 means :
* R24 and R25=100kOhm as described in the data sheet.
* The gain is approximately: 1 + R24/R25 + R24/185.5kOhm
*/
-static int max1586_v3_calc_voltage(struct max1586_data *max1586,
- unsigned selector)
-{
- unsigned range_uV = max1586->max_uV - max1586->min_uV;
-
- return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
-}
-
-static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned *selector)
+static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct max1586_data *max1586 = rdev_get_drvdata(rdev);
struct i2c_client *client = max1586->client;
- unsigned range_uV = max1586->max_uV - max1586->min_uV;
u8 v3_prog;
- if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
- return -EINVAL;
- if (min_uV < max1586->min_uV)
- min_uV = max1586->min_uV;
-
- *selector = DIV_ROUND_UP((min_uV - max1586->min_uV) *
- MAX1586_V3_MAX_VSEL, range_uV);
- if (max1586_v3_calc_voltage(max1586, *selector) > max_uV)
- return -EINVAL;
-
dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
- max1586_v3_calc_voltage(max1586, *selector) / 1000);
+ regulator_list_voltage_linear(rdev, selector) / 1000);
- v3_prog = I2C_V3_SELECT | (u8) *selector;
+ v3_prog = I2C_V3_SELECT | (u8) selector;
return i2c_smbus_write_byte(client, v3_prog);
}
-static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector)
-{
- struct max1586_data *max1586 = rdev_get_drvdata(rdev);
-
- if (selector > MAX1586_V3_MAX_VSEL)
- return -EINVAL;
- return max1586_v3_calc_voltage(max1586, selector);
-}
-
-/*
- * V6 voltage
- * On I2C bus, sending a "x" byte to the max1586 means :
- * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
- * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
- */
-static int max1586_v6_calc_voltage(unsigned selector)
-{
- static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
-
- return voltages_uv[selector];
-}
-
-static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned int *selector)
+static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
{
struct i2c_client *client = rdev_get_drvdata(rdev);
u8 v6_prog;
- if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
- return -EINVAL;
- if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
- return -EINVAL;
-
- if (min_uV < 1800000)
- *selector = 0;
- else if (min_uV < 2500000)
- *selector = 1;
- else if (min_uV < 3000000)
- *selector = 2;
- else if (min_uV >= 3000000)
- *selector = 3;
-
- if (max1586_v6_calc_voltage(*selector) > max_uV)
- return -EINVAL;
-
dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
- max1586_v6_calc_voltage(*selector) / 1000);
+ rdev->desc->volt_table[selector] / 1000);
- v6_prog = I2C_V6_SELECT | (u8) *selector;
+ v6_prog = I2C_V6_SELECT | (u8) selector;
return i2c_smbus_write_byte(client, v6_prog);
}
-static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector)
-{
- if (selector > MAX1586_V6_MAX_VSEL)
- return -EINVAL;
- return max1586_v6_calc_voltage(selector);
-}
-
/*
* The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
* the set up value.
*/
static struct regulator_ops max1586_v3_ops = {
- .set_voltage = max1586_v3_set,
- .list_voltage = max1586_v3_list,
+ .set_voltage_sel = max1586_v3_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
};
static struct regulator_ops max1586_v6_ops = {
- .set_voltage = max1586_v6_set,
- .list_voltage = max1586_v6_list,
+ .set_voltage_sel = max1586_v6_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_table,
};
-static const struct regulator_desc max1586_reg[] = {
+static struct regulator_desc max1586_reg[] = {
{
.name = "Output_V3",
.id = MAX1586_V3,
.ops = &max1586_v6_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = MAX1586_V6_MAX_VSEL + 1,
+ .volt_table = v6_voltages_uv,
.owner = THIS_MODULE,
},
};
goto err;
}
+ if (id == MAX1586_V3) {
+ max1586_reg[id].min_uV = max1586->min_uV;
+ max1586_reg[id].uV_step =
+ (max1586->max_uV - max1586->min_uV) /
+ MAX1586_V3_MAX_VSEL;
+ }
+
config.dev = &client->dev;
config.init_data = pdata->subdevs[i].platform_data;
config.driver_data = max1586;
--- /dev/null
+/*
+ * max77686.c - Regulator driver for the Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.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.
+ *
+ * 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
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+
+#define MAX77686_LDO_MINUV 800000
+#define MAX77686_LDO_UVSTEP 50000
+#define MAX77686_LDO_LOW_MINUV 800000
+#define MAX77686_LDO_LOW_UVSTEP 25000
+#define MAX77686_BUCK_MINUV 750000
+#define MAX77686_BUCK_UVSTEP 50000
+#define MAX77686_RAMP_DELAY 100000 /* uV/us */
+#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */
+#define MAX77686_DVS_MINUV 600000
+#define MAX77686_DVS_UVSTEP 12500
+
+#define MAX77686_OPMODE_SHIFT 6
+#define MAX77686_OPMODE_BUCK234_SHIFT 4
+#define MAX77686_OPMODE_MASK 0x3
+
+#define MAX77686_VSEL_MASK 0x3F
+#define MAX77686_DVS_VSEL_MASK 0xFF
+
+#define MAX77686_RAMP_RATE_MASK 0xC0
+
+#define MAX77686_REGULATORS MAX77686_REG_MAX
+#define MAX77686_LDOS 26
+
+enum max77686_ramp_rate {
+ RAMP_RATE_13P75MV,
+ RAMP_RATE_27P5MV,
+ RAMP_RATE_55MV,
+ RAMP_RATE_NO_CTRL, /* 100mV/us */
+};
+
+struct max77686_data {
+ struct regulator_dev **rdev;
+};
+
+static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ unsigned int ramp_value = RAMP_RATE_NO_CTRL;
+
+ switch (ramp_delay) {
+ case 1 ... 13750:
+ ramp_value = RAMP_RATE_13P75MV;
+ break;
+ case 13751 ... 27500:
+ ramp_value = RAMP_RATE_27P5MV;
+ break;
+ case 27501 ... 55000:
+ ramp_value = RAMP_RATE_55MV;
+ break;
+ case 55001 ... 100000:
+ break;
+ default:
+ pr_warn("%s: ramp_delay: %d not supported, setting 100000\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ MAX77686_RAMP_RATE_MASK, ramp_value << 6);
+}
+
+static struct regulator_ops max77686_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops max77686_buck_dvs_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = max77686_set_ramp_delay,
+};
+
+#define regulator_desc_ldo(num) { \
+ .name = "LDO"#num, \
+ .id = MAX77686_LDO##num, \
+ .ops = &max77686_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = MAX77686_LDO_MINUV, \
+ .uV_step = MAX77686_LDO_UVSTEP, \
+ .ramp_delay = MAX77686_RAMP_DELAY, \
+ .n_voltages = MAX77686_VSEL_MASK + 1, \
+ .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \
+ .vsel_mask = MAX77686_VSEL_MASK, \
+ .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \
+ .enable_mask = MAX77686_OPMODE_MASK \
+ << MAX77686_OPMODE_SHIFT, \
+}
+#define regulator_desc_ldo_low(num) { \
+ .name = "LDO"#num, \
+ .id = MAX77686_LDO##num, \
+ .ops = &max77686_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = MAX77686_LDO_LOW_MINUV, \
+ .uV_step = MAX77686_LDO_LOW_UVSTEP, \
+ .ramp_delay = MAX77686_RAMP_DELAY, \
+ .n_voltages = MAX77686_VSEL_MASK + 1, \
+ .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \
+ .vsel_mask = MAX77686_VSEL_MASK, \
+ .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \
+ .enable_mask = MAX77686_OPMODE_MASK \
+ << MAX77686_OPMODE_SHIFT, \
+}
+#define regulator_desc_buck(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77686_BUCK##num, \
+ .ops = &max77686_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = MAX77686_BUCK_MINUV, \
+ .uV_step = MAX77686_BUCK_UVSTEP, \
+ .ramp_delay = MAX77686_RAMP_DELAY, \
+ .n_voltages = MAX77686_VSEL_MASK + 1, \
+ .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \
+ .vsel_mask = MAX77686_VSEL_MASK, \
+ .enable_reg = MAX77686_REG_BUCK5CTRL + (num - 5) * 2, \
+ .enable_mask = MAX77686_OPMODE_MASK, \
+}
+#define regulator_desc_buck1(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77686_BUCK##num, \
+ .ops = &max77686_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = MAX77686_BUCK_MINUV, \
+ .uV_step = MAX77686_BUCK_UVSTEP, \
+ .ramp_delay = MAX77686_RAMP_DELAY, \
+ .n_voltages = MAX77686_VSEL_MASK + 1, \
+ .vsel_reg = MAX77686_REG_BUCK1OUT, \
+ .vsel_mask = MAX77686_VSEL_MASK, \
+ .enable_reg = MAX77686_REG_BUCK1CTRL, \
+ .enable_mask = MAX77686_OPMODE_MASK, \
+}
+#define regulator_desc_buck_dvs(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77686_BUCK##num, \
+ .ops = &max77686_buck_dvs_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = MAX77686_DVS_MINUV, \
+ .uV_step = MAX77686_DVS_UVSTEP, \
+ .ramp_delay = MAX77686_DVS_RAMP_DELAY, \
+ .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \
+ .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \
+ .vsel_mask = MAX77686_DVS_VSEL_MASK, \
+ .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \
+ .enable_mask = MAX77686_OPMODE_MASK \
+ << MAX77686_OPMODE_BUCK234_SHIFT, \
+}
+
+static struct regulator_desc regulators[] = {
+ regulator_desc_ldo_low(1),
+ regulator_desc_ldo_low(2),
+ regulator_desc_ldo(3),
+ regulator_desc_ldo(4),
+ regulator_desc_ldo(5),
+ regulator_desc_ldo_low(6),
+ regulator_desc_ldo_low(7),
+ regulator_desc_ldo_low(8),
+ regulator_desc_ldo(9),
+ regulator_desc_ldo(10),
+ regulator_desc_ldo(11),
+ regulator_desc_ldo(12),
+ regulator_desc_ldo(13),
+ regulator_desc_ldo(14),
+ regulator_desc_ldo_low(15),
+ regulator_desc_ldo(16),
+ regulator_desc_ldo(17),
+ regulator_desc_ldo(18),
+ regulator_desc_ldo(19),
+ regulator_desc_ldo(20),
+ regulator_desc_ldo(21),
+ regulator_desc_ldo(22),
+ regulator_desc_ldo(23),
+ regulator_desc_ldo(24),
+ regulator_desc_ldo(25),
+ regulator_desc_ldo(26),
+ regulator_desc_buck1(1),
+ regulator_desc_buck_dvs(2),
+ regulator_desc_buck_dvs(3),
+ regulator_desc_buck_dvs(4),
+ regulator_desc_buck(5),
+ regulator_desc_buck(6),
+ regulator_desc_buck(7),
+ regulator_desc_buck(8),
+ regulator_desc_buck(9),
+};
+
+#ifdef CONFIG_OF
+static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+ struct max77686_platform_data *pdata)
+{
+ struct device_node *pmic_np, *regulators_np;
+ struct max77686_regulator_data *rdata;
+ struct of_regulator_match rmatch;
+ unsigned int i;
+
+ pmic_np = iodev->dev->of_node;
+ regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+ if (!regulators_np) {
+ dev_err(iodev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ pdata->num_regulators = ARRAY_SIZE(regulators);
+ rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev,
+ "could not allocate memory for regulator data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ rmatch.name = regulators[i].name;
+ rmatch.init_data = NULL;
+ rmatch.of_node = NULL;
+ of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
+ rdata[i].initdata = rmatch.init_data;
+ }
+
+ pdata->regulators = rdata;
+
+ return 0;
+}
+#else
+static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+ struct max77686_platform_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static __devinit int max77686_pmic_probe(struct platform_device *pdev)
+{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct regulator_dev **rdev;
+ struct max77686_data *max77686;
+ int i, size;
+ int ret = 0;
+ struct regulator_config config = { };
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data found for regulator\n");
+ return -ENODEV;
+ }
+
+ if (iodev->dev->of_node) {
+ ret = max77686_pmic_dt_parse_pdata(iodev, pdata);
+ if (ret)
+ return ret;
+ }
+
+ if (pdata->num_regulators != MAX77686_REGULATORS) {
+ dev_err(&pdev->dev,
+ "Invalid initial data for regulator's initialiation\n");
+ return -EINVAL;
+ }
+
+ max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data),
+ GFP_KERNEL);
+ if (!max77686)
+ return -ENOMEM;
+
+ size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS;
+ max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!max77686->rdev)
+ return -ENOMEM;
+
+ rdev = max77686->rdev;
+ config.dev = &pdev->dev;
+ config.regmap = iodev->regmap;
+ platform_set_drvdata(pdev, max77686);
+
+ for (i = 0; i < MAX77686_REGULATORS; i++) {
+ config.init_data = pdata->regulators[i].initdata;
+
+ rdev[i] = regulator_register(®ulators[i], &config);
+ if (IS_ERR(rdev[i])) {
+ ret = PTR_ERR(rdev[i]);
+ dev_err(&pdev->dev,
+ "regulator init failed for %d\n", i);
+ rdev[i] = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+ return ret;
+}
+
+static int __devexit max77686_pmic_remove(struct platform_device *pdev)
+{
+ struct max77686_data *max77686 = platform_get_drvdata(pdev);
+ struct regulator_dev **rdev = max77686->rdev;
+ int i;
+
+ for (i = 0; i < MAX77686_REGULATORS; i++)
+ if (rdev[i])
+ regulator_unregister(rdev[i]);
+
+ return 0;
+}
+
+static const struct platform_device_id max77686_pmic_id[] = {
+ {"max77686-pmic", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, max77686_pmic_id);
+
+static struct platform_driver max77686_pmic_driver = {
+ .driver = {
+ .name = "max77686-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = max77686_pmic_probe,
+ .remove = __devexit_p(max77686_pmic_remove),
+ .id_table = max77686_pmic_id,
+};
+
+static int __init max77686_pmic_init(void)
+{
+ return platform_driver_register(&max77686_pmic_driver);
+}
+subsys_initcall(max77686_pmic_init);
+
+static void __exit max77686_pmic_cleanup(void)
+{
+ platform_driver_unregister(&max77686_pmic_driver);
+}
+module_exit(max77686_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
bool vid0;
bool vid1;
- bool en;
};
static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000;
}
-static int max8952_is_enabled(struct regulator_dev *rdev)
-{
- struct max8952_data *max8952 = rdev_get_drvdata(rdev);
- return max8952->en;
-}
-
-static int max8952_enable(struct regulator_dev *rdev)
-{
- struct max8952_data *max8952 = rdev_get_drvdata(rdev);
-
- /* If not valid, assume "ALWAYS_HIGH" */
- if (gpio_is_valid(max8952->pdata->gpio_en))
- gpio_set_value(max8952->pdata->gpio_en, 1);
-
- max8952->en = true;
- return 0;
-}
-
-static int max8952_disable(struct regulator_dev *rdev)
-{
- struct max8952_data *max8952 = rdev_get_drvdata(rdev);
-
- /* If not valid, assume "ALWAYS_HIGH" -> not permitted */
- if (gpio_is_valid(max8952->pdata->gpio_en))
- gpio_set_value(max8952->pdata->gpio_en, 0);
- else
- return -EPERM;
-
- max8952->en = false;
- return 0;
-}
-
static int max8952_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8952_data *max8952 = rdev_get_drvdata(rdev);
static struct regulator_ops max8952_ops = {
.list_voltage = max8952_list_voltage,
- .is_enabled = max8952_is_enabled,
- .enable = max8952_enable,
- .disable = max8952_disable,
.get_voltage_sel = max8952_get_voltage_sel,
.set_voltage_sel = max8952_set_voltage_sel,
- .set_suspend_disable = max8952_disable,
};
static const struct regulator_desc regulator = {
config.init_data = &pdata->reg_data;
config.driver_data = max8952;
+ config.ena_gpio = pdata->gpio_en;
+ if (pdata->reg_data.constraints.boot_on)
+ config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+
max8952->rdev = regulator_register(®ulator, &config);
if (IS_ERR(max8952->rdev)) {
return ret;
}
- max8952->en = !!(pdata->reg_data.constraints.boot_on);
max8952->vid0 = pdata->default_mode & 0x1;
max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
- if (gpio_is_valid(pdata->gpio_en)) {
- if (!gpio_request(pdata->gpio_en, "MAX8952 EN"))
- gpio_direction_output(pdata->gpio_en, max8952->en);
- else
- err = 1;
- } else
- err = 2;
-
- if (err) {
- dev_info(max8952->dev, "EN gpio invalid: assume that EN"
- "is always High\n");
- max8952->en = 1;
- pdata->gpio_en = -1; /* Mark invalid */
- }
-
- err = 0;
-
if (gpio_is_valid(pdata->gpio_vid0) &&
gpio_is_valid(pdata->gpio_vid1)) {
if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0"))
gpio_free(pdata->gpio_vid0);
gpio_free(pdata->gpio_vid1);
- gpio_free(pdata->gpio_en);
return 0;
}
*/
if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
pdata->buck5_gpiodvs) {
- bool gpio1set = false, gpio2set = false;
if (!gpio_is_valid(pdata->buck125_gpios[0]) ||
!gpio_is_valid(pdata->buck125_gpios[1]) ||
goto err_out;
}
- ret = gpio_request(pdata->buck125_gpios[0],
- "MAX8997 SET1");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request"
- " on SET1\n");
- else if (ret)
+ ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0],
+ "MAX8997 SET1");
+ if (ret)
goto err_out;
- else
- gpio1set = true;
-
- ret = gpio_request(pdata->buck125_gpios[1],
- "MAX8997 SET2");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request"
- " on SET2\n");
- else if (ret) {
- if (gpio1set)
- gpio_free(pdata->buck125_gpios[0]);
+
+ ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1],
+ "MAX8997 SET2");
+ if (ret)
goto err_out;
- } else
- gpio2set = true;
- ret = gpio_request(pdata->buck125_gpios[2],
+ ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2],
"MAX8997 SET3");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request"
- " on SET3\n");
- else if (ret) {
- if (gpio1set)
- gpio_free(pdata->buck125_gpios[0]);
- if (gpio2set)
- gpio_free(pdata->buck125_gpios[1]);
+ if (ret)
goto err_out;
- }
gpio_direction_output(pdata->buck125_gpios[0],
(max8997->buck125_gpioindex >> 2)
gpio_direction_output(pdata->buck125_gpios[2],
(max8997->buck125_gpioindex >> 0)
& 0x1); /* SET3 */
- ret = 0;
}
/* DVS-GPIO disabled */
&buck4_voltage_map_desc, /* BUCK4 */
};
-static int max8998_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- const struct voltage_map_desc *desc;
- int ldo = rdev_get_id(rdev);
- int val;
-
- if (ldo >= ARRAY_SIZE(ldo_voltage_map))
- return -EINVAL;
-
- desc = ldo_voltage_map[ldo];
- if (desc == NULL)
- return -EINVAL;
-
- val = desc->min + desc->step * selector;
- if (val > desc->max)
- return -EINVAL;
-
- return val * 1000;
-}
-
static int max8998_get_enable_register(struct regulator_dev *rdev,
int *reg, int *shift)
{
return val;
}
-static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const struct voltage_map_desc *desc;
- int ldo = rdev_get_id(rdev);
- int reg, shift = 0, mask, ret, i;
-
- if (ldo >= ARRAY_SIZE(ldo_voltage_map))
- return -EINVAL;
-
- desc = ldo_voltage_map[ldo];
- if (desc == NULL)
- return -EINVAL;
-
- if (max_vol < desc->min || min_vol > desc->max)
- return -EINVAL;
-
- if (min_vol < desc->min)
- min_vol = desc->min;
-
- i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
- if (desc->min + desc->step*i > max_vol)
- return -EINVAL;
-
- *selector = i;
+ int reg, shift = 0, mask, ret;
ret = max8998_get_voltage_register(rdev, ®, &shift, &mask);
if (ret)
return ret;
- ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+ ret = max8998_update_reg(i2c, reg, selector<<shift, mask<<shift);
return ret;
}
gpio_set_value(gpio, v & 0x1);
}
-static int max8998_set_voltage_buck(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct max8998_platform_data *pdata =
dev_get_platdata(max8998->iodev->dev);
struct i2c_client *i2c = max8998->iodev->i2c;
- int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
- const struct voltage_map_desc *desc;
int buck = rdev_get_id(rdev);
int reg, shift = 0, mask, ret;
- int i, j, previous_sel;
+ int j, previous_sel;
static u8 buck1_last_val;
- if (buck >= ARRAY_SIZE(ldo_voltage_map))
- return -EINVAL;
-
- desc = ldo_voltage_map[buck];
-
- if (desc == NULL)
- return -EINVAL;
-
- if (max_vol < desc->min || min_vol > desc->max)
- return -EINVAL;
-
- if (min_vol < desc->min)
- min_vol = desc->min;
-
- i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
- if (desc->min + desc->step*i > max_vol)
- return -EINVAL;
-
- *selector = i;
-
ret = max8998_get_voltage_register(rdev, ®, &shift, &mask);
if (ret)
return ret;
/* Check if voltage needs to be changed */
/* if previous_voltage equal new voltage, return */
- if (previous_sel == i) {
+ if (previous_sel == selector) {
dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
- max8998_list_voltage(rdev, previous_sel),
- max8998_list_voltage(rdev, i));
+ regulator_list_voltage_linear(rdev, previous_sel),
+ regulator_list_voltage_linear(rdev, selector));
return ret;
}
switch (buck) {
case MAX8998_BUCK1:
dev_dbg(max8998->dev,
- "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n"
+ "BUCK1, selector:%d, buck1_vol1:%d, buck1_vol2:%d\n"
"buck1_vol3:%d, buck1_vol4:%d\n",
- i, max8998->buck1_vol[0], max8998->buck1_vol[1],
+ selector, max8998->buck1_vol[0], max8998->buck1_vol[1],
max8998->buck1_vol[2], max8998->buck1_vol[3]);
if (gpio_is_valid(pdata->buck1_set1) &&
/* check if requested voltage */
/* value is already defined */
for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) {
- if (max8998->buck1_vol[j] == i) {
+ if (max8998->buck1_vol[j] == selector) {
max8998->buck1_idx = j;
buck1_gpio_set(pdata->buck1_set1,
pdata->buck1_set2, j);
max8998->buck1_idx = (buck1_last_val % 2) + 2;
dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
max8998->buck1_idx);
- max8998->buck1_vol[max8998->buck1_idx] = i;
+ max8998->buck1_vol[max8998->buck1_idx] = selector;
ret = max8998_get_voltage_register(rdev, ®,
&shift,
&mask);
- ret = max8998_write_reg(i2c, reg, i);
+ ret = max8998_write_reg(i2c, reg, selector);
buck1_gpio_set(pdata->buck1_set1,
pdata->buck1_set2, max8998->buck1_idx);
buck1_last_val++;
gpio_get_value(pdata->buck1_set2));
break;
} else {
- ret = max8998_write_reg(i2c, reg, i);
+ ret = max8998_write_reg(i2c, reg, selector);
}
break;
case MAX8998_BUCK2:
dev_dbg(max8998->dev,
- "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
- , i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
+ "BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n",
+ selector, max8998->buck2_vol[0], max8998->buck2_vol[1]);
if (gpio_is_valid(pdata->buck2_set3)) {
/* check if requested voltage */
/* value is already defined */
for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
- if (max8998->buck2_vol[j] == i) {
+ if (max8998->buck2_vol[j] == selector) {
max8998->buck2_idx = j;
buck2_gpio_set(pdata->buck2_set3, j);
goto buck2_exit;
max8998_get_voltage_register(rdev,
®, &shift, &mask);
- ret = max8998_write_reg(i2c, reg, i);
- max8998->buck2_vol[max8998->buck2_idx] = i;
+ ret = max8998_write_reg(i2c, reg, selector);
+ max8998->buck2_vol[max8998->buck2_idx] = selector;
buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
buck2_exit:
dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
gpio_get_value(pdata->buck2_set3));
} else {
- ret = max8998_write_reg(i2c, reg, i);
+ ret = max8998_write_reg(i2c, reg, selector);
}
break;
case MAX8998_BUCK3:
case MAX8998_BUCK4:
- ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+ ret = max8998_update_reg(i2c, reg, selector<<shift,
+ mask<<shift);
break;
}
}
static struct regulator_ops max8998_ldo_ops = {
- .list_voltage = max8998_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
.get_voltage_sel = max8998_get_voltage_sel,
- .set_voltage = max8998_set_voltage_ldo,
- .set_suspend_enable = max8998_ldo_enable,
- .set_suspend_disable = max8998_ldo_disable,
+ .set_voltage_sel = max8998_set_voltage_ldo_sel,
};
static struct regulator_ops max8998_buck_ops = {
- .list_voltage = max8998_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
.get_voltage_sel = max8998_get_voltage_sel,
- .set_voltage = max8998_set_voltage_buck,
+ .set_voltage_sel = max8998_set_voltage_buck_sel,
.set_voltage_time_sel = max8998_set_voltage_buck_time_sel,
- .set_suspend_enable = max8998_ldo_enable,
- .set_suspend_disable = max8998_ldo_disable,
};
static struct regulator_ops max8998_others_ops = {
.is_enabled = max8998_ldo_is_enabled,
.enable = max8998_ldo_enable,
.disable = max8998_ldo_disable,
- .set_suspend_enable = max8998_ldo_enable,
- .set_suspend_disable = max8998_ldo_disable,
};
static struct regulator_desc regulators[] = {
desc = ldo_voltage_map[id];
if (desc && regulators[index].ops != &max8998_others_ops) {
int count = (desc->max - desc->min) / desc->step + 1;
+
regulators[index].n_voltages = count;
+ regulators[index].min_uV = desc->min * 1000;
+ regulators[index].uV_step = desc->step * 1000;
}
config.dev = max8998->dev;
/* Voltage Values */
-static const int mc13783_sw3_val[] = {
+static const unsigned int mc13783_sw3_val[] = {
5000000, 5000000, 5000000, 5500000,
};
-static const int mc13783_vaudio_val[] = {
+static const unsigned int mc13783_vaudio_val[] = {
2775000,
};
-static const int mc13783_viohi_val[] = {
+static const unsigned int mc13783_viohi_val[] = {
2775000,
};
-static const int mc13783_violo_val[] = {
+static const unsigned int mc13783_violo_val[] = {
1200000, 1300000, 1500000, 1800000,
};
-static const int mc13783_vdig_val[] = {
+static const unsigned int mc13783_vdig_val[] = {
1200000, 1300000, 1500000, 1800000,
};
-static const int mc13783_vgen_val[] = {
+static const unsigned int mc13783_vgen_val[] = {
1200000, 1300000, 1500000, 1800000,
1100000, 2000000, 2775000, 2400000,
};
-static const int mc13783_vrfdig_val[] = {
+static const unsigned int mc13783_vrfdig_val[] = {
1200000, 1500000, 1800000, 1875000,
};
-static const int mc13783_vrfref_val[] = {
+static const unsigned int mc13783_vrfref_val[] = {
2475000, 2600000, 2700000, 2775000,
};
-static const int mc13783_vrfcp_val[] = {
+static const unsigned int mc13783_vrfcp_val[] = {
2700000, 2775000,
};
-static const int mc13783_vsim_val[] = {
+static const unsigned int mc13783_vsim_val[] = {
1800000, 2900000, 3000000,
};
-static const int mc13783_vesim_val[] = {
+static const unsigned int mc13783_vesim_val[] = {
1800000, 2900000,
};
-static const int mc13783_vcam_val[] = {
+static const unsigned int mc13783_vcam_val[] = {
1500000, 1800000, 2500000, 2550000,
2600000, 2750000, 2800000, 3000000,
};
-static const int mc13783_vrfbg_val[] = {
+static const unsigned int mc13783_vrfbg_val[] = {
1250000,
};
-static const int mc13783_vvib_val[] = {
+static const unsigned int mc13783_vvib_val[] = {
1300000, 1800000, 2000000, 3000000,
};
-static const int mc13783_vmmc_val[] = {
+static const unsigned int mc13783_vmmc_val[] = {
1600000, 1800000, 2000000, 2600000,
2700000, 2800000, 2900000, 3000000,
};
-static const int mc13783_vrf_val[] = {
+static const unsigned int mc13783_vrf_val[] = {
1500000, 1875000, 2700000, 2775000,
};
-static const int mc13783_gpo_val[] = {
+static const unsigned int mc13783_gpo_val[] = {
3100000,
};
-static const int mc13783_pwgtdrv_val[] = {
+static const unsigned int mc13783_pwgtdrv_val[] = {
5500000,
};
.enable = mc13783_gpo_regulator_enable,
.disable = mc13783_gpo_regulator_disable,
.is_enabled = mc13783_gpo_regulator_is_enabled,
- .list_voltage = mc13xxx_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage = mc13xxx_fixed_regulator_set_voltage,
.get_voltage = mc13xxx_fixed_regulator_get_voltage,
};
#define MC13892_USB1 50
#define MC13892_USB1_VUSBEN (1<<3)
-static const int mc13892_vcoincell[] = {
+static const unsigned int mc13892_vcoincell[] = {
2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
3200000, 3300000,
};
-static const int mc13892_sw1[] = {
+static const unsigned int mc13892_sw1[] = {
600000, 625000, 650000, 675000, 700000, 725000,
750000, 775000, 800000, 825000, 850000, 875000,
900000, 925000, 950000, 975000, 1000000, 1025000,
1350000, 1375000
};
-static const int mc13892_sw[] = {
+static const unsigned int mc13892_sw[] = {
600000, 625000, 650000, 675000, 700000, 725000,
750000, 775000, 800000, 825000, 850000, 875000,
900000, 925000, 950000, 975000, 1000000, 1025000,
1800000, 1825000, 1850000, 1875000
};
-static const int mc13892_swbst[] = {
+static const unsigned int mc13892_swbst[] = {
5000000,
};
-static const int mc13892_viohi[] = {
+static const unsigned int mc13892_viohi[] = {
2775000,
};
-static const int mc13892_vpll[] = {
+static const unsigned int mc13892_vpll[] = {
1050000, 1250000, 1650000, 1800000,
};
-static const int mc13892_vdig[] = {
+static const unsigned int mc13892_vdig[] = {
1050000, 1250000, 1650000, 1800000,
};
-static const int mc13892_vsd[] = {
+static const unsigned int mc13892_vsd[] = {
1800000, 2000000, 2600000, 2700000,
2800000, 2900000, 3000000, 3150000,
};
-static const int mc13892_vusb2[] = {
+static const unsigned int mc13892_vusb2[] = {
2400000, 2600000, 2700000, 2775000,
};
-static const int mc13892_vvideo[] = {
+static const unsigned int mc13892_vvideo[] = {
2700000, 2775000, 2500000, 2600000,
};
-static const int mc13892_vaudio[] = {
+static const unsigned int mc13892_vaudio[] = {
2300000, 2500000, 2775000, 3000000,
};
-static const int mc13892_vcam[] = {
+static const unsigned int mc13892_vcam[] = {
2500000, 2600000, 2750000, 3000000,
};
-static const int mc13892_vgen1[] = {
+static const unsigned int mc13892_vgen1[] = {
1200000, 1500000, 2775000, 3150000,
};
-static const int mc13892_vgen2[] = {
+static const unsigned int mc13892_vgen2[] = {
1200000, 1500000, 1600000, 1800000,
2700000, 2800000, 3000000, 3150000,
};
-static const int mc13892_vgen3[] = {
+static const unsigned int mc13892_vgen3[] = {
1800000, 2900000,
};
-static const int mc13892_vusb[] = {
+static const unsigned int mc13892_vusb[] = {
3300000,
};
-static const int mc13892_gpo[] = {
+static const unsigned int mc13892_gpo[] = {
2750000,
};
-static const int mc13892_pwgtdrv[] = {
+static const unsigned int mc13892_pwgtdrv[] = {
5000000,
};
.enable = mc13892_gpo_regulator_enable,
.disable = mc13892_gpo_regulator_disable,
.is_enabled = mc13892_gpo_regulator_is_enabled,
- .list_voltage = mc13xxx_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage = mc13xxx_fixed_regulator_set_voltage,
.get_voltage = mc13xxx_fixed_regulator_get_voltage,
};
u32 valread;
int ret;
- value = mc13892_regulators[id].voltages[selector];
+ value = rdev->desc->volt_table[selector];
mc13xxx_lock(priv->mc13xxx);
ret = mc13xxx_reg_read(priv->mc13xxx,
}
static struct regulator_ops mc13892_sw_regulator_ops = {
- .is_enabled = mc13xxx_sw_regulator_is_enabled,
- .list_voltage = mc13xxx_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
.get_voltage = mc13892_sw_regulator_get_voltage,
};
return (val & mc13xxx_regulators[id].enable_bit) != 0;
}
-int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- int id = rdev_get_id(rdev);
- struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
- struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
-
- if (selector >= mc13xxx_regulators[id].desc.n_voltages)
- return -EINVAL;
-
- return mc13xxx_regulators[id].voltages[selector];
-}
-EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
-
static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
- return mc13xxx_regulators[id].voltages[val];
+ return rdev->desc->volt_table[val];
}
struct regulator_ops mc13xxx_regulator_ops = {
.enable = mc13xxx_regulator_enable,
.disable = mc13xxx_regulator_disable,
.is_enabled = mc13xxx_regulator_is_enabled,
- .list_voltage = mc13xxx_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage_sel = mc13xxx_regulator_set_voltage_sel,
.get_voltage = mc13xxx_regulator_get_voltage,
};
int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
int max_uV, unsigned *selector)
{
- struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
- struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
int id = rdev_get_id(rdev);
dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
__func__, id, min_uV, max_uV);
- if (min_uV >= mc13xxx_regulators[id].voltages[0] &&
- max_uV <= mc13xxx_regulators[id].voltages[0])
+ if (min_uV <= rdev->desc->volt_table[0] &&
+ rdev->desc->volt_table[0] <= max_uV)
return 0;
else
return -EINVAL;
int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
{
- struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
- struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
int id = rdev_get_id(rdev);
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
- return mc13xxx_regulators[id].voltages[0];
+ return rdev->desc->volt_table[0];
}
EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
.enable = mc13xxx_regulator_enable,
.disable = mc13xxx_regulator_disable,
.is_enabled = mc13xxx_regulator_is_enabled,
- .list_voltage = mc13xxx_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage = mc13xxx_fixed_regulator_set_voltage,
.get_voltage = mc13xxx_fixed_regulator_get_voltage,
};
EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
-int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev)
-{
- return 1;
-}
-EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled);
-
#ifdef CONFIG_OF
int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
{
int vsel_shift;
int vsel_mask;
int hi_bit;
- int const *voltages;
};
struct mc13xxx_regulator_priv {
struct regulator_dev *regulators[];
};
-extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
-extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
-extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector);
extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector);
extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
.desc = { \
.name = #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
+ .volt_table = _voltages, \
.ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
.id = prefix ## _name, \
.vsel_reg = prefix ## _vsel_reg, \
.vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
.vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
- .voltages = _voltages, \
}
#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \
.desc = { \
.name = #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
+ .volt_table = _voltages, \
.ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
.id = prefix ## _name, \
}, \
.reg = prefix ## _reg, \
.enable_bit = prefix ## _reg ## _ ## _name ## EN, \
- .voltages = _voltages, \
}
#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \
.desc = { \
.name = #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
+ .volt_table = _voltages, \
.ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
.id = prefix ## _name, \
}, \
.reg = prefix ## _reg, \
.enable_bit = prefix ## _reg ## _ ## _name ## EN, \
- .voltages = _voltages, \
}
#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \
struct regulator_init_data **init_data)
{
const __be32 *min_uV, *max_uV, *uV_offset;
- const __be32 *min_uA, *max_uA;
+ const __be32 *min_uA, *max_uA, *ramp_delay;
struct regulation_constraints *constraints = &(*init_data)->constraints;
constraints->name = of_get_property(np, "regulator-name", NULL);
constraints->always_on = true;
else /* status change should be possible if not always on. */
constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+
+ ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
+ if (ramp_delay)
+ constraints->ramp_delay = be32_to_cpu(*ramp_delay);
}
/**
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
/**
- * of_regulator_match - extract regulator init data
+ * of_regulator_match - extract regulator init data when node
+ * property "regulator-compatible" matches with the regulator name.
* @dev: device requesting the data
* @node: parent device node of the regulators
* @matches: match table for the regulators
* @num_matches: number of entries in match table
*
* This function uses a match table specified by the regulator driver and
- * looks up the corresponding init data in the device tree. Note that the
- * match table is modified in place.
+ * looks up the corresponding init data in the device tree if
+ * regulator-compatible matches. Note that the match table is modified
+ * in place.
*
* Returns the number of matches found or a negative error code on failure.
*/
{
unsigned int count = 0;
unsigned int i;
+ const char *regulator_comp;
+ struct device_node *child;
if (!dev || !node)
return -EINVAL;
- for (i = 0; i < num_matches; i++) {
- struct of_regulator_match *match = &matches[i];
- struct device_node *child;
-
- child = of_find_node_by_name(node, match->name);
- if (!child)
- continue;
-
- match->init_data = of_get_regulator_init_data(dev, child);
- if (!match->init_data) {
- dev_err(dev, "failed to parse DT for regulator %s\n",
+ for_each_child_of_node(node, child) {
+ regulator_comp = of_get_property(child,
+ "regulator-compatible", NULL);
+ if (!regulator_comp) {
+ dev_err(dev, "regulator-compatible is missing for node %s\n",
child->name);
- return -EINVAL;
+ continue;
+ }
+ for (i = 0; i < num_matches; i++) {
+ struct of_regulator_match *match = &matches[i];
+ if (match->of_node)
+ continue;
+
+ if (strcmp(match->name, regulator_comp))
+ continue;
+
+ match->init_data =
+ of_get_regulator_init_data(dev, child);
+ if (!match->init_data) {
+ dev_err(dev,
+ "failed to parse DT for regulator %s\n",
+ child->name);
+ return -EINVAL;
+ }
+ match->of_node = child;
+ count++;
+ break;
}
-
- match->of_node = child;
- count++;
}
return count;
unsigned int reg;
palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®);
- reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK;
- reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+ reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
switch (mode) {
case REGULATOR_MODE_NORMAL:
static int palmas_map_voltage_smps(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
+ struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
int ret, voltage;
- ret = ((min_uV - 500000) / 10000) + 1;
- if (ret < 0)
- return ret;
+ if (min_uV == 0)
+ return 0;
+
+ if (pmic->range[id]) { /* RANGE is x2 */
+ if (min_uV < 1000000)
+ min_uV = 1000000;
+ ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 1;
+ } else { /* RANGE is x1 */
+ if (min_uV < 500000)
+ min_uV = 500000;
+ ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 1;
+ }
/* Map back into a voltage to verify we're still in bounds */
voltage = palmas_list_voltage_smps(rdev, ret);
.map_voltage = palmas_map_voltage_smps,
};
-static int palmas_list_voltage_smps10(struct regulator_dev *dev,
- unsigned selector)
-{
- return 3750000 + (selector * 1250000);
-}
-
static struct regulator_ops palmas_ops_smps10 = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = palmas_list_voltage_smps10,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
};
static int palmas_is_enabled_ldo(struct regulator_dev *dev)
if (ret)
return ret;
- if (id != PALMAS_REG_SMPS10) {
+ switch (id) {
+ case PALMAS_REG_SMPS10:
+ if (reg_init->mode_sleep) {
+ reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+ reg |= reg_init->mode_sleep <<
+ PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
+ }
+ break;
+ default:
if (reg_init->warm_reset)
reg |= PALMAS_SMPS12_CTRL_WR_S;
reg |= reg_init->mode_sleep <<
PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
}
- } else {
- if (reg_init->mode_sleep) {
- reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
- reg |= reg_init->mode_sleep <<
- PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
- }
-
}
+
ret = palmas_smps_write(palmas, addr, reg);
if (ret)
return ret;
pmic->desc[id].name = palmas_regs_info[id].name;
pmic->desc[id].id = id;
- if (id != PALMAS_REG_SMPS10) {
- pmic->desc[id].ops = &palmas_ops_smps;
- pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
- } else {
+ switch (id) {
+ case PALMAS_REG_SMPS10:
pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
pmic->desc[id].ops = &palmas_ops_smps10;
pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
PALMAS_SMPS10_STATUS);
pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+ pmic->desc[id].min_uV = 3750000;
+ pmic->desc[id].uV_step = 1250000;
+ break;
+ default:
+ pmic->desc[id].ops = &palmas_ops_smps;
+ pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
}
pmic->desc[id].type = REGULATOR_VOLTAGE;
#include <linux/regulator/machine.h>
#include <linux/mfd/ezx-pcap.h>
-static const u16 V1_table[] = {
- 2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+static const unsigned int V1_table[] = {
+ 2775000, 1275000, 1600000, 1725000, 1825000, 1925000, 2075000, 2275000,
};
-static const u16 V2_table[] = {
- 2500, 2775,
+static const unsigned int V2_table[] = {
+ 2500000, 2775000,
};
-static const u16 V3_table[] = {
- 1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+static const unsigned int V3_table[] = {
+ 1075000, 1275000, 1550000, 1725000, 1876000, 1950000, 2075000, 2275000,
};
-static const u16 V4_table[] = {
- 1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+static const unsigned int V4_table[] = {
+ 1275000, 1550000, 1725000, 1875000, 1950000, 2075000, 2275000, 2775000,
};
-static const u16 V5_table[] = {
- 1875, 2275, 2475, 2775,
+static const unsigned int V5_table[] = {
+ 1875000, 2275000, 2475000, 2775000,
};
-static const u16 V6_table[] = {
- 2475, 2775,
+static const unsigned int V6_table[] = {
+ 2475000, 2775000,
};
-static const u16 V7_table[] = {
- 1875, 2775,
+static const unsigned int V7_table[] = {
+ 1875000, 2775000,
};
#define V8_table V4_table
-static const u16 V9_table[] = {
- 1575, 1875, 2475, 2775,
+static const unsigned int V9_table[] = {
+ 1575000, 1875000, 2475000, 2775000,
};
-static const u16 V10_table[] = {
- 5000,
+static const unsigned int V10_table[] = {
+ 5000000,
};
-static const u16 VAUX1_table[] = {
- 1875, 2475, 2775, 3000,
+static const unsigned int VAUX1_table[] = {
+ 1875000, 2475000, 2775000, 3000000,
};
#define VAUX2_table VAUX1_table
-static const u16 VAUX3_table[] = {
- 1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
- 2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+static const unsigned int VAUX3_table[] = {
+ 1200000, 1200000, 1200000, 1200000, 1400000, 1600000, 1800000, 2000000,
+ 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000,
};
-static const u16 VAUX4_table[] = {
- 1800, 1800, 3000, 5000,
+static const unsigned int VAUX4_table[] = {
+ 1800000, 1800000, 3000000, 5000000,
};
-static const u16 VSIM_table[] = {
- 1875, 3000,
+static const unsigned int VSIM_table[] = {
+ 1875000, 3000000,
};
-static const u16 VSIM2_table[] = {
- 1875,
+static const unsigned int VSIM2_table[] = {
+ 1875000,
};
-static const u16 VVIB_table[] = {
- 1300, 1800, 2000, 3000,
+static const unsigned int VVIB_table[] = {
+ 1300000, 1800000, 2000000, 3000000,
};
-static const u16 SW1_table[] = {
- 900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
- 1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+static const unsigned int SW1_table[] = {
+ 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000,
+ 1300000, 1350000, 1400000, 1450000, 1500000, 1600000, 1875000, 2250000,
};
#define SW2_table SW1_table
-static const u16 SW3_table[] = {
- 4000, 4500, 5000, 5500,
+static const unsigned int SW3_table[] = {
+ 4000000, 4500000, 5000000, 5500000,
};
struct pcap_regulator {
const u8 index;
const u8 stby;
const u8 lowpwr;
- const u8 n_voltages;
- const u16 *voltage_table;
};
#define NA 0xff
.index = _index, \
.stby = _stby, \
.lowpwr = _lowpwr, \
- .n_voltages = ARRAY_SIZE(_vreg##_table), \
- .voltage_table = _vreg##_table, \
}
static struct pcap_regulator vreg_table[] = {
void *pcap = rdev_get_drvdata(rdev);
/* the regulator doesn't support voltage switching */
- if (vreg->n_voltages == 1)
+ if (rdev->desc->n_voltages == 1)
return -EINVAL;
return ezx_pcap_set_bits(pcap, vreg->reg,
- (vreg->n_voltages - 1) << vreg->index,
+ (rdev->desc->n_voltages - 1) << vreg->index,
selector << vreg->index);
}
void *pcap = rdev_get_drvdata(rdev);
u32 tmp;
- if (vreg->n_voltages == 1)
+ if (rdev->desc->n_voltages == 1)
return 0;
ezx_pcap_read(pcap, vreg->reg, &tmp);
- tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+ tmp = ((tmp >> vreg->index) & (rdev->desc->n_voltages - 1));
return tmp;
}
return (tmp >> vreg->en) & 1;
}
-static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned int index)
-{
- struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
-
- return vreg->voltage_table[index] * 1000;
-}
-
static struct regulator_ops pcap_regulator_ops = {
- .list_voltage = pcap_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_voltage_sel = pcap_regulator_set_voltage_sel,
.get_voltage_sel = pcap_regulator_get_voltage_sel,
.enable = pcap_regulator_enable,
.name = #_vreg, \
.id = _vreg, \
.n_voltages = ARRAY_SIZE(_vreg##_table), \
+ .volt_table = _vreg##_table, \
.ops = &pcap_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
return 900 + (bits * 100);
}
-static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
struct pcf50633 *pcf;
int regulator_id, millivolts;
- u8 volt_bits, regnr;
+ u8 volt_bits;
pcf = rdev_get_drvdata(rdev);
millivolts = min_uV / 1000;
- regnr = rdev->desc->vsel_reg;
-
switch (regulator_id) {
case PCF50633_REGULATOR_AUTO:
volt_bits = auto_voltage_bits(millivolts);
break;
case PCF50633_REGULATOR_DOWN1:
- volt_bits = down_voltage_bits(millivolts);
- break;
case PCF50633_REGULATOR_DOWN2:
volt_bits = down_voltage_bits(millivolts);
break;
return -EINVAL;
}
- *selector = volt_bits;
-
- return pcf50633_reg_write(pcf, regnr, volt_bits);
+ return volt_bits;
}
static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
millivolts = auto_voltage_value(index);
break;
case PCF50633_REGULATOR_DOWN1:
- millivolts = down_voltage_value(index);
- break;
case PCF50633_REGULATOR_DOWN2:
millivolts = down_voltage_value(index);
break;
}
static struct regulator_ops pcf50633_regulator_ops = {
- .set_voltage = pcf50633_regulator_set_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = pcf50633_regulator_list_voltage,
+ .map_voltage = pcf50633_regulator_map_voltage,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
/* Regulator specific turn-on delay and voltage settling time*/
int enable_uv_per_us;
- int change_uv_per_us;
/* Used by regulator core */
struct regulator_desc desc;
return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
}
-static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector, unsigned int new_selector)
-{
- struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
- int old_uV, new_uV;
- old_uV = regulator_list_voltage_linear(rdev, old_selector);
-
- if (old_uV < 0)
- return old_uV;
-
- new_uV = regulator_list_voltage_linear(rdev, new_selector);
- if (new_uV < 0)
- return new_uV;
-
- return DIV_ROUND_UP(abs(old_uV - new_uV),
- reg->reg_info->change_uv_per_us);
-}
-
-
static struct regulator_ops rc5t583_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
- .set_voltage_time_sel = rc5t583_set_voltage_time_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
};
#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \
.disc_bit = _disc_bit, \
.deepsleep_reg = RC5T583_REG_##_id##DAC_DS, \
.enable_uv_per_us = _enable_mv * 1000, \
- .change_uv_per_us = 40 * 1000, \
.deepsleep_id = RC5T583_DS_##_id, \
.desc = { \
.name = "rc5t583-regulator-"#_id, \
.enable_mask = BIT(_en_bit), \
.min_uV = _min_mv * 1000, \
.uV_step = _step_uV, \
+ .ramp_delay = 40 * 1000, \
}, \
}
--- /dev/null
+/*
+ * s2mps11.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ * http://www.samsung.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/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mps11.h>
+
+struct s2mps11_info {
+ struct regulator_dev **rdev;
+
+ int ramp_delay2;
+ int ramp_delay34;
+ int ramp_delay5;
+ int ramp_delay16;
+ int ramp_delay7810;
+ int ramp_delay9;
+
+ bool buck6_ramp;
+ bool buck2_ramp;
+ bool buck3_ramp;
+ bool buck4_ramp;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+ unsigned char cnt = 0;
+
+ ramp_delay /= 6;
+
+ while (true) {
+ ramp_delay = ramp_delay >> 1;
+ if (ramp_delay == 0)
+ break;
+ cnt++;
+ }
+ return cnt;
+}
+
+static struct regulator_ops s2mps11_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mps11_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+#define regulator_desc_ldo1(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS11_LDO##num, \
+ .ops = &s2mps11_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_LDO_MIN, \
+ .uV_step = S2MPS11_LDO_STEP1, \
+ .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS11_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+#define regulator_desc_ldo2(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS11_LDO##num, \
+ .ops = &s2mps11_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_LDO_MIN, \
+ .uV_step = S2MPS11_LDO_STEP2, \
+ .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS11_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+#define regulator_desc_buck1_4(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS11_BUCK##num, \
+ .ops = &s2mps11_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_BUCK_MIN1, \
+ .uV_step = S2MPS11_BUCK_STEP1, \
+ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+#define regulator_desc_buck5 { \
+ .name = "BUCK5", \
+ .id = S2MPS11_BUCK5, \
+ .ops = &s2mps11_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_BUCK_MIN1, \
+ .uV_step = S2MPS11_BUCK_STEP1, \
+ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_B5CTRL2, \
+ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_B5CTRL1, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+#define regulator_desc_buck6_8(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS11_BUCK##num, \
+ .ops = &s2mps11_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_BUCK_MIN1, \
+ .uV_step = S2MPS11_BUCK_STEP1, \
+ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \
+ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_B6CTRL1 + (num - 6) * 2, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+#define regulator_desc_buck9 { \
+ .name = "BUCK9", \
+ .id = S2MPS11_BUCK9, \
+ .ops = &s2mps11_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_BUCK_MIN3, \
+ .uV_step = S2MPS11_BUCK_STEP3, \
+ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_B9CTRL2, \
+ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_B9CTRL1, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+#define regulator_desc_buck10 { \
+ .name = "BUCK10", \
+ .id = S2MPS11_BUCK10, \
+ .ops = &s2mps11_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS11_BUCK_MIN2, \
+ .uV_step = S2MPS11_BUCK_STEP2, \
+ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .vsel_reg = S2MPS11_REG_B9CTRL2, \
+ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS11_REG_B9CTRL1, \
+ .enable_mask = S2MPS11_ENABLE_MASK \
+}
+
+static struct regulator_desc regulators[] = {
+ regulator_desc_ldo2(1),
+ regulator_desc_ldo1(2),
+ regulator_desc_ldo1(3),
+ regulator_desc_ldo1(4),
+ regulator_desc_ldo1(5),
+ regulator_desc_ldo2(6),
+ regulator_desc_ldo1(7),
+ regulator_desc_ldo1(8),
+ regulator_desc_ldo1(9),
+ regulator_desc_ldo1(10),
+ regulator_desc_ldo2(11),
+ regulator_desc_ldo1(12),
+ regulator_desc_ldo1(13),
+ regulator_desc_ldo1(14),
+ regulator_desc_ldo1(15),
+ regulator_desc_ldo1(16),
+ regulator_desc_ldo1(17),
+ regulator_desc_ldo1(18),
+ regulator_desc_ldo1(19),
+ regulator_desc_ldo1(20),
+ regulator_desc_ldo1(21),
+ regulator_desc_ldo2(22),
+ regulator_desc_ldo2(23),
+ regulator_desc_ldo1(24),
+ regulator_desc_ldo1(25),
+ regulator_desc_ldo1(26),
+ regulator_desc_ldo2(27),
+ regulator_desc_ldo1(28),
+ regulator_desc_ldo1(29),
+ regulator_desc_ldo1(30),
+ regulator_desc_ldo1(31),
+ regulator_desc_ldo1(32),
+ regulator_desc_ldo1(33),
+ regulator_desc_ldo1(34),
+ regulator_desc_ldo1(35),
+ regulator_desc_ldo1(36),
+ regulator_desc_ldo1(37),
+ regulator_desc_ldo1(38),
+ regulator_desc_buck1_4(1),
+ regulator_desc_buck1_4(2),
+ regulator_desc_buck1_4(3),
+ regulator_desc_buck1_4(4),
+ regulator_desc_buck5,
+ regulator_desc_buck6_8(6),
+ regulator_desc_buck6_8(7),
+ regulator_desc_buck6_8(8),
+ regulator_desc_buck9,
+ regulator_desc_buck10,
+};
+
+static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
+{
+ struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct regulator_config config = { };
+ struct regulator_dev **rdev;
+ struct s2mps11_info *s2mps11;
+ int i, ret, size;
+ unsigned char ramp_enable, ramp_reg = 0;
+
+ if (!pdata) {
+ dev_err(pdev->dev.parent, "Platform data not supplied\n");
+ return -ENODEV;
+ }
+
+ s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
+ GFP_KERNEL);
+ if (!s2mps11)
+ return -ENOMEM;
+
+ size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX;
+ s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!s2mps11->rdev) {
+ return -ENOMEM;
+ }
+
+ rdev = s2mps11->rdev;
+ platform_set_drvdata(pdev, s2mps11);
+
+ s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
+ s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
+ s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
+ s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
+ s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
+ s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
+
+ s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
+ s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
+ s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
+ s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
+
+ ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
+ (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
+
+ if (ramp_enable) {
+ if (s2mps11->buck2_ramp)
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6;
+ if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4;
+ sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
+ }
+
+ ramp_reg &= 0x00;
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6;
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4;
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2;
+ ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
+ sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
+
+ for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+
+ config.dev = &pdev->dev;
+ config.regmap = iodev->regmap;
+ config.init_data = pdata->regulators[i].initdata;
+ config.driver_data = s2mps11;
+
+ rdev[i] = regulator_register(®ulators[i], &config);
+ if (IS_ERR(rdev[i])) {
+ ret = PTR_ERR(rdev[i]);
+ dev_err(&pdev->dev, "regulator init failed for %d\n",
+ i);
+ rdev[i] = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
+ if (rdev[i])
+ regulator_unregister(rdev[i]);
+
+ return ret;
+}
+
+static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
+{
+ struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
+ struct regulator_dev **rdev = s2mps11->rdev;
+ int i;
+
+ for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
+ if (rdev[i])
+ regulator_unregister(rdev[i]);
+
+ return 0;
+}
+
+static const struct platform_device_id s2mps11_pmic_id[] = {
+ { "s2mps11-pmic", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
+
+static struct platform_driver s2mps11_pmic_driver = {
+ .driver = {
+ .name = "s2mps11-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = s2mps11_pmic_probe,
+ .remove = __devexit_p(s2mps11_pmic_remove),
+ .id_table = s2mps11_pmic_id,
+};
+
+static int __init s2mps11_pmic_init(void)
+{
+ return platform_driver_register(&s2mps11_pmic_driver);
+}
+subsys_initcall(s2mps11_pmic_init);
+
+static void __exit s2mps11_pmic_exit(void)
+{
+ platform_driver_unregister(&s2mps11_pmic_driver);
+}
+module_exit(s2mps11_pmic_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_LICENSE("GPL");
u8 buck3_vol[8];
u8 buck4_vol[8];
int buck_gpios[3];
+ int buck_ds[3];
int buck_gpioindex;
};
[S5M8767_BUCK9] = &buck_voltage_val3,
};
-static int s5m8767_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- const struct s5m_voltage_desc *desc;
- int reg_id = rdev_get_id(rdev);
- int val;
-
- if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
- return -EINVAL;
-
- desc = reg_voltage_map[reg_id];
- if (desc == NULL)
- return -EINVAL;
-
- val = desc->min + desc->step * selector;
- if (val > desc->max)
- return -EINVAL;
-
- return val;
-}
-
static unsigned int s5m8767_opmode_reg[][4] = {
/* {OFF, ON, LOWPOWER, SUSPEND} */
/* LDO1 ... LDO28 */
reg = S5M8767_REG_BUCK1CTRL2;
break;
case S5M8767_BUCK2:
- reg = S5M8767_REG_BUCK2DVS1;
+ reg = S5M8767_REG_BUCK2DVS2;
if (s5m8767->buck2_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
case S5M8767_BUCK3:
- reg = S5M8767_REG_BUCK3DVS1;
+ reg = S5M8767_REG_BUCK3DVS2;
if (s5m8767->buck3_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
case S5M8767_BUCK4:
- reg = S5M8767_REG_BUCK4DVS1;
+ reg = S5M8767_REG_BUCK4DVS2;
if (s5m8767->buck4_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
return selector;
}
-static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
{
int temp_index = s5m8767->buck_gpioindex;
gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+
+ return 0;
}
-static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
{
int temp_index = s5m8767->buck_gpioindex;
gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+
+ return 0;
}
-static int s5m8767_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- const struct s5m_voltage_desc *desc;
int reg_id = rdev_get_id(rdev);
- int sel, reg, mask, ret = 0, old_index, index = 0;
- u8 val;
+ int reg, mask, ret = 0, old_index, index = 0;
u8 *buck234_vol = NULL;
switch (reg_id) {
return -EINVAL;
}
- desc = reg_voltage_map[reg_id];
-
- sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
- if (sel < 0)
- return sel;
-
/* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
if (buck234_vol) {
- while (*buck234_vol != sel) {
+ while (*buck234_vol != selector) {
buck234_vol++;
index++;
}
s5m8767->buck_gpioindex = index;
if (index > old_index)
- s5m8767_set_high(s5m8767);
+ return s5m8767_set_high(s5m8767);
else
- s5m8767_set_low(s5m8767);
+ return s5m8767_set_low(s5m8767);
} else {
ret = s5m8767_get_voltage_register(rdev, ®);
if (ret)
return ret;
- s5m_reg_read(s5m8767->iodev, reg, &val);
- val = (val & ~mask) | sel;
-
- ret = s5m_reg_write(s5m8767->iodev, reg, val);
+ return s5m_reg_update(s5m8767->iodev, reg, selector, mask);
}
-
- *selector = sel;
- return ret;
}
static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
}
static struct regulator_ops s5m8767_ops = {
- .list_voltage = s5m8767_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
.is_enabled = s5m8767_reg_is_enabled,
.enable = s5m8767_reg_enable,
.disable = s5m8767_reg_disable,
.get_voltage_sel = s5m8767_get_voltage_sel,
- .set_voltage = s5m8767_set_voltage,
+ .set_voltage_sel = s5m8767_set_voltage_sel,
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
};
+static struct regulator_ops s5m8767_buck78_ops = {
+ .is_enabled = s5m8767_reg_is_enabled,
+ .enable = s5m8767_reg_enable,
+ .disable = s5m8767_reg_disable,
+};
+
#define s5m8767_regulator_desc(_name) { \
.name = #_name, \
.id = S5M8767_##_name, \
.owner = THIS_MODULE, \
}
+#define s5m8767_regulator_buck78_desc(_name) { \
+ .name = #_name, \
+ .id = S5M8767_##_name, \
+ .ops = &s5m8767_buck78_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+}
+
static struct regulator_desc regulators[] = {
s5m8767_regulator_desc(LDO1),
s5m8767_regulator_desc(LDO2),
s5m8767_regulator_desc(BUCK4),
s5m8767_regulator_desc(BUCK5),
s5m8767_regulator_desc(BUCK6),
- s5m8767_regulator_desc(BUCK7),
- s5m8767_regulator_desc(BUCK8),
+ s5m8767_regulator_buck78_desc(BUCK7),
+ s5m8767_regulator_buck78_desc(BUCK8),
s5m8767_regulator_desc(BUCK9),
};
struct regulator_config config = { };
struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
- int i, ret, size;
+ int i, ret, size, buck_init;
if (!pdata) {
dev_err(pdev->dev.parent, "Platform data not supplied\n");
s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
+ s5m8767->buck_ds[0] = pdata->buck_ds[0];
+ s5m8767->buck_ds[1] = pdata->buck_ds[1];
+ s5m8767->buck_ds[2] = pdata->buck_ds[2];
+
s5m8767->ramp_delay = pdata->buck_ramp_delay;
s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
s5m8767->opmode = pdata->opmode;
+ buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+ pdata->buck2_init,
+ pdata->buck2_init +
+ buck_voltage_val2.step);
+
+ s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
+
+ buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+ pdata->buck3_init,
+ pdata->buck3_init +
+ buck_voltage_val2.step);
+
+ s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
+
+ buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+ pdata->buck4_init,
+ pdata->buck4_init +
+ buck_voltage_val2.step);
+
+ s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
+
for (i = 0; i < 8; i++) {
if (s5m8767->buck2_gpiodvs) {
s5m8767->buck2_vol[i] =
}
}
- if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
- pdata->buck4_gpiodvs) {
- if (gpio_is_valid(pdata->buck_gpios[0]) &&
- gpio_is_valid(pdata->buck_gpios[1]) &&
- gpio_is_valid(pdata->buck_gpios[2])) {
- ret = gpio_request(pdata->buck_gpios[0],
- "S5M8767 SET1");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
-
- ret = gpio_request(pdata->buck_gpios[1],
- "S5M8767 SET2");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
-
- ret = gpio_request(pdata->buck_gpios[2],
- "S5M8767 SET3");
- if (ret == -EBUSY)
- dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
- /* SET1 GPIO */
- gpio_direction_output(pdata->buck_gpios[0],
- (s5m8767->buck_gpioindex >> 2) & 0x1);
- /* SET2 GPIO */
- gpio_direction_output(pdata->buck_gpios[1],
- (s5m8767->buck_gpioindex >> 1) & 0x1);
- /* SET3 GPIO */
- gpio_direction_output(pdata->buck_gpios[2],
- (s5m8767->buck_gpioindex >> 0) & 0x1);
- ret = 0;
- } else {
- dev_err(&pdev->dev, "GPIO NOT VALID\n");
- ret = -EINVAL;
+ if (gpio_is_valid(pdata->buck_gpios[0]) &&
+ gpio_is_valid(pdata->buck_gpios[1]) &&
+ gpio_is_valid(pdata->buck_gpios[2])) {
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0],
+ "S5M8767 SET1");
+ if (ret)
return ret;
- }
+
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1],
+ "S5M8767 SET2");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2],
+ "S5M8767 SET3");
+ if (ret)
+ return ret;
+
+ /* SET1 GPIO */
+ gpio_direction_output(pdata->buck_gpios[0],
+ (s5m8767->buck_gpioindex >> 2) & 0x1);
+ /* SET2 GPIO */
+ gpio_direction_output(pdata->buck_gpios[1],
+ (s5m8767->buck_gpioindex >> 1) & 0x1);
+ /* SET3 GPIO */
+ gpio_direction_output(pdata->buck_gpios[2],
+ (s5m8767->buck_gpioindex >> 0) & 0x1);
+ } else {
+ dev_err(&pdev->dev, "GPIO NOT VALID\n");
+ ret = -EINVAL;
+ return ret;
}
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
- (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
- (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
- (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4");
+ if (ret)
+ return ret;
+
+ /* DS2 GPIO */
+ gpio_direction_output(pdata->buck_ds[0], 0x0);
+ /* DS3 GPIO */
+ gpio_direction_output(pdata->buck_ds[1], 0x0);
+ /* DS4 GPIO */
+ gpio_direction_output(pdata->buck_ds[2], 0x0);
+
+ if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+ pdata->buck4_gpiodvs) {
+ s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+ (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
+ 1 << 1);
+ s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+ (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
+ 1 << 1);
+ s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+ (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
+ 1 << 1);
+ }
/* Initialize GPIO DVS registers */
for (i = 0; i < 8; i++) {
s5m8767->buck4_vol[i]);
}
}
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
- s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
if (s5m8767->buck2_ramp)
s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
|| s5m8767->buck4_ramp) {
switch (s5m8767->ramp_delay) {
- case 15:
+ case 5:
s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
- 0xc0, 0xf0);
+ 0x40, 0xf0);
+ break;
+ case 10:
+ s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+ 0x90, 0xf0);
break;
case 25:
s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
int id = pdata->regulators[i].id;
desc = reg_voltage_map[id];
- if (desc)
+ if (desc) {
regulators[id].n_voltages =
(desc->max - desc->min) / desc->step + 1;
+ regulators[id].min_uV = desc->min;
+ regulators[id].uV_step = desc->step;
+ }
config.dev = s5m8767->dev;
config.init_data = pdata->regulators[i].initdata;
#include <linux/mfd/core.h>
#include <linux/mfd/tps6105x.h>
-static const int tps6105x_voltages[] = {
+static const unsigned int tps6105x_voltages[] = {
4500000,
5000000,
5250000,
return 0;
}
-static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector >= ARRAY_SIZE(tps6105x_voltages))
- return -EINVAL;
-
- return tps6105x_voltages[selector];
-}
-
static struct regulator_ops tps6105x_regulator_ops = {
.enable = tps6105x_regulator_enable,
.disable = tps6105x_regulator_disable,
.is_enabled = tps6105x_regulator_is_enabled,
.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
- .list_voltage = tps6105x_regulator_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
static const struct regulator_desc tps6105x_regulator_desc = {
.id = 0,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(tps6105x_voltages),
+ .volt_table = tps6105x_voltages,
};
/*
struct regulator_desc desc;
struct regulator_dev *rdev;
struct regmap *regmap;
- int chip_id;
int vsel0_gpio;
int vsel1_gpio;
- int voltage_base;
u8 voltage_reg_mask;
bool en_internal_pulldn;
bool en_discharge;
int lru_index[4];
int curr_vset_vsel[4];
int curr_vset_id;
- int change_uv_per_us;
};
/*
return 0;
}
-static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector, unsigned int new_selector)
-{
- struct tps62360_chip *tps = rdev_get_drvdata(rdev);
- int old_uV, new_uV;
-
- old_uV = regulator_list_voltage_linear(rdev, old_selector);
- if (old_uV < 0)
- return old_uV;
-
- new_uV = regulator_list_voltage_linear(rdev, new_selector);
- if (new_uV < 0)
- return new_uV;
-
- return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us);
-}
-
static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct tps62360_chip *tps = rdev_get_drvdata(rdev);
.set_voltage_sel = tps62360_dcdc_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
- .set_voltage_time_sel = tps62360_set_voltage_time_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_mode = tps62360_set_mode,
.get_mode = tps62360_get_mode,
};
ramp_ctrl = (ramp_ctrl >> 4) & 0x7;
/* ramp mV/us = 32/(2^ramp_ctrl) */
- tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
+ tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
return ret;
}
switch (chip_id) {
case TPS62360:
case TPS62362:
- tps->voltage_base = TPS62360_BASE_VOLTAGE;
+ tps->desc.min_uV = TPS62360_BASE_VOLTAGE;
tps->voltage_reg_mask = 0x3F;
tps->desc.n_voltages = TPS62360_N_VOLTAGES;
break;
case TPS62361:
case TPS62363:
- tps->voltage_base = TPS62361_BASE_VOLTAGE;
+ tps->desc.min_uV = TPS62361_BASE_VOLTAGE;
tps->voltage_reg_mask = 0x7F;
tps->desc.n_voltages = TPS62361_N_VOLTAGES;
break;
tps->desc.ops = &tps62360_dcdc_ops;
tps->desc.type = REGULATOR_VOLTAGE;
tps->desc.owner = THIS_MODULE;
- tps->desc.min_uV = tps->voltage_base;
tps->desc.uV_step = 10000;
tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
int gpio_flags;
gpio_flags = (pdata->vsel0_def_state) ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- ret = gpio_request_one(tps->vsel0_gpio,
+ ret = devm_gpio_request_one(&client->dev, tps->vsel0_gpio,
gpio_flags, "tps62360-vsel0");
if (ret) {
dev_err(&client->dev,
"%s(): Could not obtain vsel0 GPIO %d: %d\n",
__func__, tps->vsel0_gpio, ret);
- goto err_gpio0;
+ return ret;
}
gpio_flags = (pdata->vsel1_def_state) ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- ret = gpio_request_one(tps->vsel1_gpio,
+ ret = devm_gpio_request_one(&client->dev, tps->vsel1_gpio,
gpio_flags, "tps62360-vsel1");
if (ret) {
dev_err(&client->dev,
"%s(): Could not obtain vsel1 GPIO %d: %d\n",
__func__, tps->vsel1_gpio, ret);
- goto err_gpio1;
+ return ret;
}
tps->valid_gpios = true;
if (ret < 0) {
dev_err(tps->dev, "%s(): Init failed with err = %d\n",
__func__, ret);
- goto err_init;
+ return ret;
}
config.dev = &client->dev;
dev_err(tps->dev,
"%s(): regulator register failed with err %s\n",
__func__, id->name);
- ret = PTR_ERR(rdev);
- goto err_init;
+ return PTR_ERR(rdev);
}
tps->rdev = rdev;
return 0;
-
-err_init:
- if (gpio_is_valid(tps->vsel1_gpio))
- gpio_free(tps->vsel1_gpio);
-err_gpio1:
- if (gpio_is_valid(tps->vsel0_gpio))
- gpio_free(tps->vsel0_gpio);
-err_gpio0:
- return ret;
}
/**
{
struct tps62360_chip *tps = i2c_get_clientdata(client);
- if (gpio_is_valid(tps->vsel1_gpio))
- gpio_free(tps->vsel1_gpio);
-
- if (gpio_is_valid(tps->vsel0_gpio))
- gpio_free(tps->vsel0_gpio);
-
regulator_unregister(tps->rdev);
return 0;
}
#define TPS65023_REG_CTRL2_DCDC1 BIT(1)
#define TPS65023_REG_CTRL2_DCDC3 BIT(0)
-/* LDO_CTRL bitfields */
-#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
-#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0x07 << ((ldo_id)*4))
-
/* Number of step-down converters available */
#define TPS65023_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
/* Supported voltage values for regulators */
-static const u16 VCORE_VSEL_table[] = {
- 800, 825, 850, 875,
- 900, 925, 950, 975,
- 1000, 1025, 1050, 1075,
- 1100, 1125, 1150, 1175,
- 1200, 1225, 1250, 1275,
- 1300, 1325, 1350, 1375,
- 1400, 1425, 1450, 1475,
- 1500, 1525, 1550, 1600,
+static const unsigned int VCORE_VSEL_table[] = {
+ 800000, 825000, 850000, 875000,
+ 900000, 925000, 950000, 975000,
+ 1000000, 1025000, 1050000, 1075000,
+ 1100000, 1125000, 1150000, 1175000,
+ 1200000, 1225000, 1250000, 1275000,
+ 1300000, 1325000, 1350000, 1375000,
+ 1400000, 1425000, 1450000, 1475000,
+ 1500000, 1525000, 1550000, 1600000,
+};
+
+static const unsigned int DCDC_FIXED_3300000_VSEL_table[] = {
+ 3300000,
+};
+
+static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = {
+ 1800000,
};
/* Supported voltage values for LDO regulators for tps65020 */
-static const u16 TPS65020_LDO1_VSEL_table[] = {
- 1000, 1050, 1100, 1300,
- 1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO1_VSEL_table[] = {
+ 1000000, 1050000, 1100000, 1300000,
+ 1800000, 2500000, 3000000, 3300000,
};
-static const u16 TPS65020_LDO2_VSEL_table[] = {
- 1000, 1050, 1100, 1300,
- 1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO2_VSEL_table[] = {
+ 1000000, 1050000, 1100000, 1300000,
+ 1800000, 2500000, 3000000, 3300000,
};
/* Supported voltage values for LDO regulators
* for tps65021 and tps65023 */
-static const u16 TPS65023_LDO1_VSEL_table[] = {
- 1000, 1100, 1300, 1800,
- 2200, 2600, 2800, 3150,
+static const unsigned int TPS65023_LDO1_VSEL_table[] = {
+ 1000000, 1100000, 1300000, 1800000,
+ 2200000, 2600000, 2800000, 3150000,
};
-static const u16 TPS65023_LDO2_VSEL_table[] = {
- 1050, 1200, 1300, 1800,
- 2500, 2800, 3000, 3300,
+static const unsigned int TPS65023_LDO2_VSEL_table[] = {
+ 1050000, 1200000, 1300000, 1800000,
+ 2500000, 2800000, 3000000, 3300000,
};
/* Regulator specific details */
struct tps_info {
const char *name;
- unsigned min_uV;
- unsigned max_uV;
- bool fixed;
u8 table_len;
- const u16 *table;
+ const unsigned int *table;
};
/* PMIC details */
u8 core_regulator;
};
-static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
+static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ret;
if (ret != 0)
return ret;
data &= (tps->info[dcdc]->table_len - 1);
- return tps->info[dcdc]->table[data] * 1000;
+ return data;
} else
- return tps->info[dcdc]->min_uV;
+ return 0;
}
static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
return ret;
}
-static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int data, ldo = rdev_get_id(dev);
- int ret;
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
-
- ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
- if (ret != 0)
- return ret;
-
- data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
- data &= (tps->info[ldo]->table_len - 1);
- return tps->info[ldo]->table[data] * 1000;
-}
-
-static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
-
- return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
- TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
- selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
-}
-
-static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int dcdc = rdev_get_id(dev);
-
- if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
- return -EINVAL;
-
- if (dcdc == tps->core_regulator) {
- if (selector >= tps->info[dcdc]->table_len)
- return -EINVAL;
- else
- return tps->info[dcdc]->table[selector] * 1000;
- } else
- return tps->info[dcdc]->min_uV;
-}
-
-static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps_pmic *tps = rdev_get_drvdata(dev);
- int ldo = rdev_get_id(dev);
-
- if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
- return -EINVAL;
-
- if (selector >= tps->info[ldo]->table_len)
- return -EINVAL;
- else
- return tps->info[ldo]->table[selector] * 1000;
-}
-
/* Operations permitted on VDCDCx */
static struct regulator_ops tps65023_dcdc_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .get_voltage = tps65023_dcdc_get_voltage,
+ .get_voltage_sel = tps65023_dcdc_get_voltage_sel,
.set_voltage_sel = tps65023_dcdc_set_voltage_sel,
- .list_voltage = tps65023_dcdc_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
/* Operations permitted on LDOx */
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .get_voltage = tps65023_ldo_get_voltage,
- .set_voltage_sel = tps65023_ldo_set_voltage_sel,
- .list_voltage = tps65023_ldo_list_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_table,
};
static struct regmap_config tps65023_regmap_config = {
tps->desc[i].name = info->name;
tps->desc[i].id = i;
tps->desc[i].n_voltages = info->table_len;
+ tps->desc[i].volt_table = info->table;
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
- if (i == TPS65023_LDO_1)
+ switch (i) {
+ case TPS65023_LDO_1:
+ tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+ tps->desc[i].vsel_mask = 0x07;
tps->desc[i].enable_mask = 1 << 1;
- else if (i == TPS65023_LDO_2)
+ break;
+ case TPS65023_LDO_2:
+ tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+ tps->desc[i].vsel_mask = 0x70;
tps->desc[i].enable_mask = 1 << 2;
- else /* DCDCx */
+ break;
+ default: /* DCDCx */
tps->desc[i].enable_mask =
1 << (TPS65023_NUM_REGULATOR - i);
+ }
config.dev = &client->dev;
config.init_data = init_data;
static const struct tps_info tps65020_regs[] = {
{
.name = "VDCDC1",
- .min_uV = 3300000,
- .max_uV = 3300000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+ .table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+ .table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
- .min_uV = 800000,
- .max_uV = 1600000,
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
-
{
.name = "LDO1",
- .min_uV = 1000000,
- .max_uV = 3150000,
.table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
.table = TPS65020_LDO1_VSEL_table,
},
{
.name = "LDO2",
- .min_uV = 1050000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
.table = TPS65020_LDO2_VSEL_table,
},
static const struct tps_info tps65021_regs[] = {
{
.name = "VDCDC1",
- .min_uV = 3300000,
- .max_uV = 3300000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+ .table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC2",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+ .table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "VDCDC3",
- .min_uV = 800000,
- .max_uV = 1600000,
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
- .min_uV = 1000000,
- .max_uV = 3150000,
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
- .min_uV = 1050000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
static const struct tps_info tps65023_regs[] = {
{
.name = "VDCDC1",
- .min_uV = 800000,
- .max_uV = 1600000,
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "VDCDC2",
- .min_uV = 3300000,
- .max_uV = 3300000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+ .table = DCDC_FIXED_3300000_VSEL_table,
},
{
.name = "VDCDC3",
- .min_uV = 1800000,
- .max_uV = 1800000,
- .fixed = 1,
+ .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+ .table = DCDC_FIXED_1800000_VSEL_table,
},
{
.name = "LDO1",
- .min_uV = 1000000,
- .max_uV = 3150000,
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
- .min_uV = 1050000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
/* Number of total regulators available */
#define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
-/* Supported voltage values for regulators (in milliVolts) */
-static const u16 VDCDCx_VSEL_table[] = {
- 725, 750, 775, 800,
- 825, 850, 875, 900,
- 925, 950, 975, 1000,
- 1025, 1050, 1075, 1100,
- 1125, 1150, 1175, 1200,
- 1225, 1250, 1275, 1300,
- 1325, 1350, 1375, 1400,
- 1425, 1450, 1475, 1500,
- 1550, 1600, 1650, 1700,
- 1750, 1800, 1850, 1900,
- 1950, 2000, 2050, 2100,
- 2150, 2200, 2250, 2300,
- 2350, 2400, 2450, 2500,
- 2550, 2600, 2650, 2700,
- 2750, 2800, 2850, 2900,
- 3000, 3100, 3200, 3300,
+/* Supported voltage values for regulators (in microVolts) */
+static const unsigned int VDCDCx_VSEL_table[] = {
+ 725000, 750000, 775000, 800000,
+ 825000, 850000, 875000, 900000,
+ 925000, 950000, 975000, 1000000,
+ 1025000, 1050000, 1075000, 1100000,
+ 1125000, 1150000, 1175000, 1200000,
+ 1225000, 1250000, 1275000, 1300000,
+ 1325000, 1350000, 1375000, 1400000,
+ 1425000, 1450000, 1475000, 1500000,
+ 1550000, 1600000, 1650000, 1700000,
+ 1750000, 1800000, 1850000, 1900000,
+ 1950000, 2000000, 2050000, 2100000,
+ 2150000, 2200000, 2250000, 2300000,
+ 2350000, 2400000, 2450000, 2500000,
+ 2550000, 2600000, 2650000, 2700000,
+ 2750000, 2800000, 2850000, 2900000,
+ 3000000, 3100000, 3200000, 3300000,
};
-static const u16 LDO1_VSEL_table[] = {
- 1000, 1100, 1200, 1250,
- 1300, 1350, 1400, 1500,
- 1600, 1800, 2500, 2750,
- 2800, 3000, 3100, 3300,
+static const unsigned int LDO1_VSEL_table[] = {
+ 1000000, 1100000, 1200000, 1250000,
+ 1300000, 1350000, 1400000, 1500000,
+ 1600000, 1800000, 2500000, 2750000,
+ 2800000, 3000000, 3100000, 3300000,
};
-static const u16 LDO2_VSEL_table[] = {
- 725, 750, 775, 800,
- 825, 850, 875, 900,
- 925, 950, 975, 1000,
- 1025, 1050, 1075, 1100,
- 1125, 1150, 1175, 1200,
- 1225, 1250, 1275, 1300,
- 1325, 1350, 1375, 1400,
- 1425, 1450, 1475, 1500,
- 1550, 1600, 1650, 1700,
- 1750, 1800, 1850, 1900,
- 1950, 2000, 2050, 2100,
- 2150, 2200, 2250, 2300,
- 2350, 2400, 2450, 2500,
- 2550, 2600, 2650, 2700,
- 2750, 2800, 2850, 2900,
- 3000, 3100, 3200, 3300,
-};
+/* The voltage mapping table for LDO2 is the same as VDCDCx */
+#define LDO2_VSEL_table VDCDCx_VSEL_table
struct tps_info {
const char *name;
- unsigned min_uV;
- unsigned max_uV;
u8 table_len;
- const u16 *table;
+ const unsigned int *table;
/* Does DCDC high or the low register defines output voltage? */
bool defdcdc_default;
static struct tps_info tps6507x_pmic_regs[] = {
{
.name = "VDCDC1",
- .min_uV = 725000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC2",
- .min_uV = 725000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC3",
- .min_uV = 725000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "LDO1",
- .min_uV = 1000000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
.table = LDO1_VSEL_table,
},
{
.name = "LDO2",
- .min_uV = 725000,
- .max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table),
.table = LDO2_VSEL_table,
},
return tps6507x_pmic_reg_write(tps, reg, data);
}
-static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
- int rid = rdev_get_id(dev);
-
- if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
- return -EINVAL;
-
- if (selector >= tps->info[rid]->table_len)
- return -EINVAL;
- else
- return tps->info[rid]->table[selector] * 1000;
-}
-
static struct regulator_ops tps6507x_pmic_ops = {
.is_enabled = tps6507x_pmic_is_enabled,
.enable = tps6507x_pmic_enable,
.disable = tps6507x_pmic_disable,
.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
- .list_voltage = tps6507x_pmic_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
tps->desc[i].name = info->name;
tps->desc[i].id = i;
tps->desc[i].n_voltages = info->table_len;
+ tps->desc[i].volt_table = info->table;
tps->desc[i].ops = &tps6507x_pmic_ops;
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>
-#define TPS65217_REGULATOR(_name, _id, _ops, _n) \
+#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \
{ \
.name = _name, \
.id = _id, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .enable_reg = TPS65217_REG_ENABLE, \
+ .enable_mask = _em, \
+ .volt_table = _t, \
} \
-#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm) \
+#define TPS65217_INFO(_nm, _min, _max, _f1, _f2) \
{ \
.name = _nm, \
.min_uV = _min, \
.max_uV = _max, \
.vsel_to_uv = _f1, \
.uv_to_vsel = _f2, \
- .table = _t, \
- .table_len = _n, \
- .enable_mask = _em, \
- .set_vout_reg = _vr, \
- .set_vout_mask = _vm, \
}
-static const int LDO1_VSEL_table[] = {
+static const unsigned int LDO1_VSEL_table[] = {
1000000, 1100000, 1200000, 1250000,
1300000, 1350000, 1400000, 1500000,
1600000, 1800000, 2500000, 2750000,
static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
{
- if ((uV < 0) && (uV > 3300000))
+ if (uV < 0 || uV > 3300000)
return -EINVAL;
if (uV <= 1500000)
static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
{
- if ((uV < 0) && (uV > 3300000))
+ if (uV < 0 || uV > 3300000)
return -EINVAL;
if (uV <= 1900000)
static struct tps_info tps65217_pmic_regs[] = {
TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN,
- TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK),
+ tps65217_uv_to_vsel1),
TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN,
- TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK),
+ tps65217_uv_to_vsel1),
TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN,
- TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK),
- TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table,
- 16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1,
- TPS65217_DEFLDO1_LDO1_MASK),
+ tps65217_uv_to_vsel1),
+ TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL),
TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN,
- TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK),
+ tps65217_uv_to_vsel1),
TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
- tps65217_uv_to_vsel2, NULL, 32,
- TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
- TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK),
+ tps65217_uv_to_vsel2),
TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
- tps65217_uv_to_vsel2, NULL, 32,
- TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
- TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK),
+ tps65217_uv_to_vsel2),
};
-static int tps65217_pmic_is_enabled(struct regulator_dev *dev)
-{
- int ret;
- struct tps65217 *tps = rdev_get_drvdata(dev);
- unsigned int data, rid = rdev_get_id(dev);
-
- if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
- return -EINVAL;
-
- ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data);
- if (ret)
- return ret;
-
- return (data & tps->info[rid]->enable_mask) ? 1 : 0;
-}
-
static int tps65217_pmic_enable(struct regulator_dev *dev)
{
struct tps65217 *tps = rdev_get_drvdata(dev);
/* Enable the regulator and password protection is level 1 */
return tps65217_set_bits(tps, TPS65217_REG_ENABLE,
- tps->info[rid]->enable_mask,
- tps->info[rid]->enable_mask,
- TPS65217_PROTECT_L1);
+ dev->desc->enable_mask, dev->desc->enable_mask,
+ TPS65217_PROTECT_L1);
}
static int tps65217_pmic_disable(struct regulator_dev *dev)
/* Disable the regulator and password protection is level 1 */
return tps65217_clear_bits(tps, TPS65217_REG_ENABLE,
- tps->info[rid]->enable_mask, TPS65217_PROTECT_L1);
-}
-
-static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev)
-{
- int ret;
- struct tps65217 *tps = rdev_get_drvdata(dev);
- unsigned int selector, rid = rdev_get_id(dev);
-
- if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
- return -EINVAL;
-
- ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector);
- if (ret)
- return ret;
-
- selector &= tps->info[rid]->set_vout_mask;
-
- return selector;
+ dev->desc->enable_mask, TPS65217_PROTECT_L1);
}
static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
unsigned int rid = rdev_get_id(dev);
/* Set the voltage based on vsel value and write protect level is 2 */
- ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
- tps->info[rid]->set_vout_mask,
+ ret = tps65217_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
selector, TPS65217_PROTECT_L2);
/* Set GO bit for DCDCx to initiate voltage transistion */
if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
return -EINVAL;
- if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
- return -EINVAL;
+ if (min_uV < tps->info[rid]->min_uV)
+ min_uV = tps->info[rid]->min_uV;
- if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV)
+ if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
return -EINVAL;
ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
return -EINVAL;
- if (selector >= tps->info[rid]->table_len)
+ if (selector >= dev->desc->n_voltages)
return -EINVAL;
- if (tps->info[rid]->table)
- return tps->info[rid]->table[selector];
-
return tps->info[rid]->vsel_to_uv(selector);
}
/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
static struct regulator_ops tps65217_pmic_ops = {
- .is_enabled = tps65217_pmic_is_enabled,
+ .is_enabled = regulator_is_enabled_regmap,
.enable = tps65217_pmic_enable,
.disable = tps65217_pmic_disable,
- .get_voltage_sel = tps65217_pmic_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = tps65217_pmic_list_voltage,
.map_voltage = tps65217_pmic_map_voltage,
/* Operations permitted on LDO1 */
static struct regulator_ops tps65217_pmic_ldo1_ops = {
- .is_enabled = tps65217_pmic_is_enabled,
+ .is_enabled = regulator_is_enabled_regmap,
.enable = tps65217_pmic_enable,
.disable = tps65217_pmic_disable,
- .get_voltage_sel = tps65217_pmic_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
- .list_voltage = tps65217_pmic_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
static const struct regulator_desc regulators[] = {
- TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64),
- TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64),
- TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64),
- TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16),
- TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64),
- TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32),
- TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32),
+ TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
+ TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
+ TPS65217_ENABLE_DC1_EN, NULL),
+ TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
+ TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
+ TPS65217_ENABLE_DC2_EN, NULL),
+ TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
+ TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
+ TPS65217_ENABLE_DC3_EN, NULL),
+ TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
+ TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
+ TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table),
+ TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
+ TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
+ TPS65217_ENABLE_LDO2_EN, NULL),
+ TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
+ TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
+ TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
+ NULL),
+ TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
+ TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
+ TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
+ NULL),
};
static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
tps->info[pdev->id] = info;
config.dev = &pdev->dev;
+ config.of_node = pdev->dev.of_node;
config.init_data = pdev->dev.platform_data;
config.driver_data = tps;
#define N_SWITCH 2
#define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH)
-#define FIXED_ILIMSEL BIT(0)
-#define FIXED_VOLTAGE BIT(1)
-
#define CMD_READ(reg) ((reg) << 6)
#define CMD_WRITE(reg) (BIT(5) | (reg) << 6)
#define STAT_CLK BIT(3)
struct supply_info {
const char *name;
int n_voltages;
- const int *voltages;
- int fixed_voltage;
+ const unsigned int *voltages;
int n_ilimsels;
- const int *ilimsels;
- int fixed_ilimsel;
- int flags;
+ const unsigned int *ilimsels;
struct field enable, voltage, ilimsel;
};
val << field->shift);
}
-static const int dcdc1_voltages[] = {
+static const unsigned int dcdc1_voltages[] = {
800000, 825000, 850000, 875000,
900000, 925000, 950000, 975000,
1000000, 1025000, 1050000, 1075000,
1500000, 1525000, 1550000, 1575000,
};
-static const int dcdc2_voltages[] = {
+static const unsigned int dcdc2_voltages[] = {
1400000, 1450000, 1500000, 1550000,
1600000, 1650000, 1700000, 1750000,
1800000, 1850000, 1900000, 1950000,
2800000, 2850000, 2900000, 2950000,
};
-static const int dcdc3_voltages[] = {
+static const unsigned int dcdc3_voltages[] = {
2400000, 2450000, 2500000, 2550000, 2600000,
2650000, 2700000, 2750000, 2800000, 2850000,
2900000, 2950000, 3000000, 3050000, 3100000,
3400000, 3450000, 3500000, 3550000, 3600000,
};
-static const int ldo1_voltages[] = {
+static const unsigned int ldo1_voltages[] = {
4300000, 4350000, 4400000, 4450000,
4500000, 4550000, 4600000, 4650000,
4700000, 4750000, 4800000, 4850000,
4900000, 4950000, 5000000, 5050000,
};
-static const int ldo2_voltages[] = {
+static const unsigned int ldo2_voltages[] = {
1100000, 1150000, 1200000, 1250000,
1300000, 1700000, 1750000, 1800000,
1850000, 1900000, 3150000, 3200000,
3250000, 3300000, 3350000, 3400000,
};
-static const int ldo_ilimsel[] = {
+static const unsigned int fixed_5000000_voltage[] = {
+ 5000000
+};
+
+static const unsigned int ldo_ilimsel[] = {
400000, 1500000
};
-static const int usb_ilimsel[] = {
+static const unsigned int usb_ilimsel[] = {
200000, 400000, 800000, 1000000
};
+static const unsigned int fixed_2400000_ilimsel[] = {
+ 2400000
+};
+
+static const unsigned int fixed_1200000_ilimsel[] = {
+ 1200000
+};
+
+static const unsigned int fixed_400000_ilimsel[] = {
+ 400000
+};
+
#define __MK_FIELD(_reg, _mask, _shift) \
{ .reg = (_reg), .mask = (_mask), .shift = (_shift), }
static const struct supply_info supply_info[N_REGULATORS] = {
{
.name = "DCDC1",
- .flags = FIXED_ILIMSEL,
.n_voltages = ARRAY_SIZE(dcdc1_voltages),
.voltages = dcdc1_voltages,
- .fixed_ilimsel = 2400000,
+ .n_ilimsels = ARRAY_SIZE(fixed_2400000_ilimsel),
+ .ilimsels = fixed_2400000_ilimsel,
.enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
DCDCDCDC1_EN_SHIFT),
.voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
},
{
.name = "DCDC2",
- .flags = FIXED_ILIMSEL,
.n_voltages = ARRAY_SIZE(dcdc2_voltages),
.voltages = dcdc2_voltages,
- .fixed_ilimsel = 1200000,
+ .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel),
+ .ilimsels = fixed_1200000_ilimsel,
.enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
DCDCDCDC2_EN_SHIFT),
.voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
},
{
.name = "DCDC3",
- .flags = FIXED_ILIMSEL,
.n_voltages = ARRAY_SIZE(dcdc3_voltages),
.voltages = dcdc3_voltages,
- .fixed_ilimsel = 1200000,
+ .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel),
+ .ilimsels = fixed_1200000_ilimsel,
.enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
DCDCDCDC3_EN_SHIFT),
.voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
},
{
.name = "USB",
- .flags = FIXED_VOLTAGE,
- .fixed_voltage = 5000000,
+ .n_voltages = ARRAY_SIZE(fixed_5000000_voltage),
+ .voltages = fixed_5000000_voltage,
.n_ilimsels = ARRAY_SIZE(usb_ilimsel),
.ilimsels = usb_ilimsel,
.enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
},
{
.name = "LCD",
- .flags = FIXED_VOLTAGE | FIXED_ILIMSEL,
- .fixed_voltage = 5000000,
- .fixed_ilimsel = 400000,
+ .n_voltages = ARRAY_SIZE(fixed_5000000_voltage),
+ .voltages = fixed_5000000_voltage,
+ .n_ilimsels = ARRAY_SIZE(fixed_400000_ilimsel),
+ .ilimsels = fixed_400000_ilimsel,
.enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
BLOCK_LCD_SHIFT),
},
};
-static int list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
- const struct supply_info *info;
- struct tps6524x *hw;
-
- hw = rdev_get_drvdata(rdev);
- info = &supply_info[rdev_get_id(rdev)];
-
- if (info->flags & FIXED_VOLTAGE)
- return selector ? -EINVAL : info->fixed_voltage;
-
- return ((selector < info->n_voltages) ?
- info->voltages[selector] : -EINVAL);
-}
-
static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
const struct supply_info *info;
hw = rdev_get_drvdata(rdev);
info = &supply_info[rdev_get_id(rdev)];
- if (info->flags & FIXED_VOLTAGE)
+ if (rdev->desc->n_voltages == 1)
return -EINVAL;
return write_field(hw, &info->voltage, selector);
hw = rdev_get_drvdata(rdev);
info = &supply_info[rdev_get_id(rdev)];
- if (info->flags & FIXED_VOLTAGE)
+ if (rdev->desc->n_voltages == 1)
return 0;
ret = read_field(hw, &info->voltage);
hw = rdev_get_drvdata(rdev);
info = &supply_info[rdev_get_id(rdev)];
- if (info->flags & FIXED_ILIMSEL)
+ if (info->n_ilimsels == 1)
return -EINVAL;
for (i = 0; i < info->n_ilimsels; i++)
hw = rdev_get_drvdata(rdev);
info = &supply_info[rdev_get_id(rdev)];
- if (info->flags & FIXED_ILIMSEL)
- return info->fixed_ilimsel;
+ if (info->n_ilimsels == 1)
+ return info->ilimsels[0];
ret = read_field(hw, &info->ilimsel);
if (ret < 0)
.disable = disable_supply,
.get_voltage_sel = get_voltage_sel,
.set_voltage_sel = set_voltage_sel,
- .list_voltage = list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.set_current_limit = set_current_limit,
.get_current_limit = get_current_limit,
};
hw->desc[i].name = info->name;
hw->desc[i].id = i;
hw->desc[i].n_voltages = info->n_voltages;
+ hw->desc[i].volt_table = info->voltages;
hw->desc[i].ops = ®ulator_ops;
hw->desc[i].type = REGULATOR_VOLTAGE;
hw->desc[i].owner = THIS_MODULE;
- if (info->flags & FIXED_VOLTAGE)
- hw->desc[i].n_voltages = 1;
-
config.dev = dev;
config.init_data = init_data;
config.driver_data = hw;
int enable_bit[2];
int enable_reg[2];
- int *voltages;
-
/* for DVM regulators */
int go_reg;
int go_bit;
static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
{
- return rdev_get_dev(rdev)->parent->parent;
+ return rdev_get_dev(rdev)->parent;
}
-static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
- struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
- int rid = rdev_get_id(rdev);
-
- /* LDO0 has minimal voltage 1.2V rather than 1.25V */
- if ((rid == TPS6586X_ID_LDO_0) && (selector == 0))
- return (info->voltages[0] - 50) * 1000;
-
- return info->voltages[selector] * 1000;
-}
-
-
static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
}
static struct regulator_ops tps6586x_regulator_ops = {
- .list_voltage = tps6586x_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
.get_voltage_sel = tps6586x_get_voltage_sel,
.set_voltage_sel = tps6586x_set_voltage_sel,
.disable = tps6586x_regulator_disable,
};
-static int tps6586x_ldo_voltages[] = {
- 1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
+static const unsigned int tps6586x_ldo0_voltages[] = {
+ 1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
+};
+
+static const unsigned int tps6586x_ldo4_voltages[] = {
+ 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+ 1900000, 1925000, 1950000, 1975000, 2000000, 2025000, 2050000, 2075000,
+ 2100000, 2125000, 2150000, 2175000, 2200000, 2225000, 2250000, 2275000,
+ 2300000, 2325000, 2350000, 2375000, 2400000, 2425000, 2450000, 2475000,
};
-static int tps6586x_ldo4_voltages[] = {
- 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
- 1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
- 2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
- 2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
+static const unsigned int tps6586x_ldo_voltages[] = {
+ 1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
};
-static int tps6586x_sm2_voltages[] = {
- 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
- 3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
- 3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
- 4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
+static const unsigned int tps6586x_sm2_voltages[] = {
+ 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000, 3350000,
+ 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000, 3750000,
+ 3800000, 3850000, 3900000, 3950000, 4000000, 4050000, 4100000, 4150000,
+ 4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
};
-static int tps6586x_dvm_voltages[] = {
- 725, 750, 775, 800, 825, 850, 875, 900,
- 925, 950, 975, 1000, 1025, 1050, 1075, 1100,
- 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
- 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int tps6586x_dvm_voltages[] = {
+ 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000,
+ 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+ 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+ 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
};
-#define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
+#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
.desc = { \
+ .supply_name = _pin_name, \
.name = "REG-" #_id, \
.ops = &tps6586x_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = TPS6586X_ID_##_id, \
.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \
+ .volt_table = tps6586x_##vdata##_voltages, \
.owner = THIS_MODULE, \
}, \
.volt_reg = TPS6586X_##vreg, \
.enable_reg[0] = TPS6586X_SUPPLY##ereg0, \
.enable_bit[0] = (ebit0), \
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
- .enable_bit[1] = (ebit1), \
- .voltages = tps6586x_##vdata##_voltages,
+ .enable_bit[1] = (ebit1),
#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
.go_reg = TPS6586X_##goreg, \
.go_bit = (gobit),
-#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
+#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
- TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
}
-#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
+#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
- TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \
+ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
}
static struct tps6586x_regulator tps6586x_regulator[] = {
- TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
- TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
- TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
- TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
- TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
- TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
- TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
- TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
- TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
- TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
-
- TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
- TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
- TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
- TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+ TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0),
+ TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
+ TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+ TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
+ TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
+ TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
+ TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
+ TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
+ TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
+ TPS6586X_LDO(SM_2, "sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
+
+ TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
+ ENB, 3, VCC2, 6),
+ TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
+ END, 3, VCC1, 6),
+ TPS6586X_DVM(SM_0, "sm0", dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
+ TPS6586X_DVM(SM_1, "sm1", dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
};
/*
if (err)
return err;
- config.dev = &pdev->dev;
+ config.dev = pdev->dev.parent;
config.of_node = pdev->dev.of_node;
config.init_data = pdev->dev.platform_data;
config.driver_data = ri;
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
-/* supported VIO voltages in millivolts */
-static const u16 VIO_VSEL_table[] = {
- 1500, 1800, 2500, 3300,
+/* supported VIO voltages in microvolts */
+static const unsigned int VIO_VSEL_table[] = {
+ 1500000, 1800000, 2500000, 3300000,
};
/* VSEL tables for TPS65910 specific LDOs and dcdc's */
-/* supported VDD3 voltages in millivolts */
-static const u16 VDD3_VSEL_table[] = {
- 5000,
+/* supported VDD3 voltages in microvolts */
+static const unsigned int VDD3_VSEL_table[] = {
+ 5000000,
};
-/* supported VDIG1 voltages in millivolts */
-static const u16 VDIG1_VSEL_table[] = {
- 1200, 1500, 1800, 2700,
+/* supported VDIG1 voltages in microvolts */
+static const unsigned int VDIG1_VSEL_table[] = {
+ 1200000, 1500000, 1800000, 2700000,
};
-/* supported VDIG2 voltages in millivolts */
-static const u16 VDIG2_VSEL_table[] = {
- 1000, 1100, 1200, 1800,
+/* supported VDIG2 voltages in microvolts */
+static const unsigned int VDIG2_VSEL_table[] = {
+ 1000000, 1100000, 1200000, 1800000,
};
-/* supported VPLL voltages in millivolts */
-static const u16 VPLL_VSEL_table[] = {
- 1000, 1100, 1800, 2500,
+/* supported VPLL voltages in microvolts */
+static const unsigned int VPLL_VSEL_table[] = {
+ 1000000, 1100000, 1800000, 2500000,
};
-/* supported VDAC voltages in millivolts */
-static const u16 VDAC_VSEL_table[] = {
- 1800, 2600, 2800, 2850,
+/* supported VDAC voltages in microvolts */
+static const unsigned int VDAC_VSEL_table[] = {
+ 1800000, 2600000, 2800000, 2850000,
};
-/* supported VAUX1 voltages in millivolts */
-static const u16 VAUX1_VSEL_table[] = {
- 1800, 2500, 2800, 2850,
+/* supported VAUX1 voltages in microvolts */
+static const unsigned int VAUX1_VSEL_table[] = {
+ 1800000, 2500000, 2800000, 2850000,
};
-/* supported VAUX2 voltages in millivolts */
-static const u16 VAUX2_VSEL_table[] = {
- 1800, 2800, 2900, 3300,
+/* supported VAUX2 voltages in microvolts */
+static const unsigned int VAUX2_VSEL_table[] = {
+ 1800000, 2800000, 2900000, 3300000,
};
-/* supported VAUX33 voltages in millivolts */
-static const u16 VAUX33_VSEL_table[] = {
- 1800, 2000, 2800, 3300,
+/* supported VAUX33 voltages in microvolts */
+static const unsigned int VAUX33_VSEL_table[] = {
+ 1800000, 2000000, 2800000, 3300000,
};
-/* supported VMMC voltages in millivolts */
-static const u16 VMMC_VSEL_table[] = {
- 1800, 2800, 3000, 3300,
+/* supported VMMC voltages in microvolts */
+static const unsigned int VMMC_VSEL_table[] = {
+ 1800000, 2800000, 3000000, 3300000,
};
struct tps_info {
const char *name;
- unsigned min_uV;
- unsigned max_uV;
+ const char *vin_name;
u8 n_voltages;
- const u16 *voltage_table;
+ const unsigned int *voltage_table;
int enable_time_us;
};
static struct tps_info tps65910_regs[] = {
{
.name = "vrtc",
+ .vin_name = "vcc7",
.enable_time_us = 2200,
},
{
.name = "vio",
- .min_uV = 1500000,
- .max_uV = 3300000,
+ .vin_name = "vccio",
.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
.voltage_table = VIO_VSEL_table,
.enable_time_us = 350,
},
{
.name = "vdd1",
- .min_uV = 600000,
- .max_uV = 4500000,
+ .vin_name = "vcc1",
.enable_time_us = 350,
},
{
.name = "vdd2",
- .min_uV = 600000,
- .max_uV = 4500000,
+ .vin_name = "vcc2",
.enable_time_us = 350,
},
{
.name = "vdd3",
- .min_uV = 5000000,
- .max_uV = 5000000,
.n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
.voltage_table = VDD3_VSEL_table,
.enable_time_us = 200,
},
{
.name = "vdig1",
- .min_uV = 1200000,
- .max_uV = 2700000,
+ .vin_name = "vcc6",
.n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
.voltage_table = VDIG1_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vdig2",
- .min_uV = 1000000,
- .max_uV = 1800000,
+ .vin_name = "vcc6",
.n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
.voltage_table = VDIG2_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vpll",
- .min_uV = 1000000,
- .max_uV = 2500000,
+ .vin_name = "vcc5",
.n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
.voltage_table = VPLL_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vdac",
- .min_uV = 1800000,
- .max_uV = 2850000,
+ .vin_name = "vcc5",
.n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
.voltage_table = VDAC_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vaux1",
- .min_uV = 1800000,
- .max_uV = 2850000,
+ .vin_name = "vcc4",
.n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
.voltage_table = VAUX1_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vaux2",
- .min_uV = 1800000,
- .max_uV = 3300000,
+ .vin_name = "vcc4",
.n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
.voltage_table = VAUX2_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vaux33",
- .min_uV = 1800000,
- .max_uV = 3300000,
+ .vin_name = "vcc3",
.n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
.voltage_table = VAUX33_VSEL_table,
.enable_time_us = 100,
},
{
.name = "vmmc",
- .min_uV = 1800000,
- .max_uV = 3300000,
+ .vin_name = "vcc3",
.n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
.voltage_table = VMMC_VSEL_table,
.enable_time_us = 100,
static struct tps_info tps65911_regs[] = {
{
.name = "vrtc",
+ .vin_name = "vcc7",
.enable_time_us = 2200,
},
{
.name = "vio",
- .min_uV = 1500000,
- .max_uV = 3300000,
+ .vin_name = "vccio",
.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
.voltage_table = VIO_VSEL_table,
.enable_time_us = 350,
},
{
.name = "vdd1",
- .min_uV = 600000,
- .max_uV = 4500000,
- .n_voltages = 73,
+ .vin_name = "vcc1",
+ .n_voltages = 0x4C,
.enable_time_us = 350,
},
{
.name = "vdd2",
- .min_uV = 600000,
- .max_uV = 4500000,
- .n_voltages = 73,
+ .vin_name = "vcc2",
+ .n_voltages = 0x4C,
.enable_time_us = 350,
},
{
.name = "vddctrl",
- .min_uV = 600000,
- .max_uV = 1400000,
- .n_voltages = 65,
+ .n_voltages = 0x44,
.enable_time_us = 900,
},
{
.name = "ldo1",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 47,
+ .vin_name = "vcc6",
+ .n_voltages = 0x33,
.enable_time_us = 420,
},
{
.name = "ldo2",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 47,
+ .vin_name = "vcc6",
+ .n_voltages = 0x33,
.enable_time_us = 420,
},
{
.name = "ldo3",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 24,
+ .vin_name = "vcc5",
+ .n_voltages = 0x1A,
.enable_time_us = 230,
},
{
.name = "ldo4",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 47,
+ .vin_name = "vcc5",
+ .n_voltages = 0x33,
.enable_time_us = 230,
},
{
.name = "ldo5",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 24,
+ .vin_name = "vcc4",
+ .n_voltages = 0x1A,
.enable_time_us = 230,
},
{
.name = "ldo6",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 24,
+ .vin_name = "vcc3",
+ .n_voltages = 0x1A,
.enable_time_us = 230,
},
{
.name = "ldo7",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 24,
+ .vin_name = "vcc3",
+ .n_voltages = 0x1A,
.enable_time_us = 230,
},
{
.name = "ldo8",
- .min_uV = 1000000,
- .max_uV = 3300000,
- .n_voltages = 24,
+ .vin_name = "vcc3",
+ .n_voltages = 0x1A,
.enable_time_us = 230,
},
};
struct tps65910 *mfd;
struct regulator_dev **rdev;
struct tps_info **info;
- struct mutex mutex;
int num_regulators;
int mode;
int (*get_ctrl_reg)(int);
unsigned int board_ext_control[TPS65910_NUM_REGS];
};
-static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
-{
- unsigned int val;
- int err;
-
- err = tps65910_reg_read(pmic->mfd, reg, &val);
- if (err)
- return err;
-
- return val;
-}
-
-static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
- u8 set_mask, u8 clear_mask)
-{
- int err, data;
-
- mutex_lock(&pmic->mutex);
-
- data = tps65910_read(pmic, reg);
- if (data < 0) {
- dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
- err = data;
- goto out;
- }
-
- data &= ~clear_mask;
- data |= set_mask;
- err = tps65910_reg_write(pmic->mfd, reg, data);
- if (err)
- dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
-
-out:
- mutex_unlock(&pmic->mutex);
- return err;
-}
-
-static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg)
-{
- int data;
-
- mutex_lock(&pmic->mutex);
-
- data = tps65910_read(pmic, reg);
- if (data < 0)
- dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
-
- mutex_unlock(&pmic->mutex);
- return data;
-}
-
-static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val)
-{
- int err;
-
- mutex_lock(&pmic->mutex);
-
- err = tps65910_reg_write(pmic->mfd, reg, val);
- if (err < 0)
- dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
-
- mutex_unlock(&pmic->mutex);
- return err;
-}
-
static int tps65910_get_ctrl_register(int id)
{
switch (id) {
}
}
-static int tps65910_enable_time(struct regulator_dev *dev)
-{
- struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- return pmic->info[id]->enable_time_us;
-}
-
static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
switch (mode) {
case REGULATOR_MODE_NORMAL:
- return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT,
- LDO_ST_MODE_BIT);
+ return tps65910_reg_update_bits(pmic->mfd, reg,
+ LDO_ST_MODE_BIT | LDO_ST_ON_BIT,
+ LDO_ST_ON_BIT);
case REGULATOR_MODE_IDLE:
value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
return tps65910_reg_set_bits(mfd, reg, value);
static unsigned int tps65910_get_mode(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int reg, value, id = rdev_get_id(dev);
+ int ret, reg, value, id = rdev_get_id(dev);
reg = pmic->get_ctrl_reg(id);
if (reg < 0)
return reg;
- value = tps65910_reg_read_locked(pmic, reg);
- if (value < 0)
- return value;
+ ret = tps65910_reg_read(pmic->mfd, reg, &value);
+ if (ret < 0)
+ return ret;
if (!(value & LDO_ST_ON_BIT))
return REGULATOR_MODE_STANDBY;
static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
+ int ret, id = rdev_get_id(dev);
int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
switch (id) {
case TPS65910_REG_VDD1:
- opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP);
- mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1);
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_OP, &opvsel);
+ if (ret < 0)
+ return ret;
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1, &mult);
+ if (ret < 0)
+ return ret;
mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
- srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR);
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_SR, &srvsel);
+ if (ret < 0)
+ return ret;
sr = opvsel & VDD1_OP_CMD_MASK;
opvsel &= VDD1_OP_SEL_MASK;
srvsel &= VDD1_SR_SEL_MASK;
vselmax = 75;
break;
case TPS65910_REG_VDD2:
- opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP);
- mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2);
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_OP, &opvsel);
+ if (ret < 0)
+ return ret;
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2, &mult);
+ if (ret < 0)
+ return ret;
mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
- srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR);
+ ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_SR, &srvsel);
+ if (ret < 0)
+ return ret;
sr = opvsel & VDD2_OP_CMD_MASK;
opvsel &= VDD2_OP_SEL_MASK;
srvsel &= VDD2_SR_SEL_MASK;
vselmax = 75;
break;
case TPS65911_REG_VDDCTRL:
- opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP);
- srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR);
+ ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_OP,
+ &opvsel);
+ if (ret < 0)
+ return ret;
+ ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_SR,
+ &srvsel);
+ if (ret < 0)
+ return ret;
sr = opvsel & VDDCTRL_OP_CMD_MASK;
opvsel &= VDDCTRL_OP_SEL_MASK;
srvsel &= VDDCTRL_SR_SEL_MASK;
static int tps65910_get_voltage_sel(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int reg, value, id = rdev_get_id(dev);
+ int ret, reg, value, id = rdev_get_id(dev);
reg = pmic->get_ctrl_reg(id);
if (reg < 0)
return reg;
- value = tps65910_reg_read_locked(pmic, reg);
- if (value < 0)
- return value;
+ ret = tps65910_reg_read(pmic->mfd, reg, &value);
+ if (ret < 0)
+ return ret;
switch (id) {
case TPS65910_REG_VIO:
static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
{
- return 5 * 1000 * 1000;
+ return dev->desc->volt_table[0];
}
static int tps65911_get_voltage_sel(struct regulator_dev *dev)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- u8 value, reg;
+ int ret, id = rdev_get_id(dev);
+ unsigned int value, reg;
reg = pmic->get_ctrl_reg(id);
- value = tps65910_reg_read_locked(pmic, reg);
+ ret = tps65910_reg_read(pmic->mfd, reg, &value);
+ if (ret < 0)
+ return ret;
switch (id) {
case TPS65911_REG_LDO1:
dcdc_mult--;
vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
- tps65910_modify_bits(pmic, TPS65910_VDD1,
- (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
- VDD1_VGAIN_SEL_MASK);
- tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel);
+ tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD1,
+ VDD1_VGAIN_SEL_MASK,
+ dcdc_mult << VDD1_VGAIN_SEL_SHIFT);
+ tps65910_reg_write(pmic->mfd, TPS65910_VDD1_OP, vsel);
break;
case TPS65910_REG_VDD2:
dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
dcdc_mult--;
vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
- tps65910_modify_bits(pmic, TPS65910_VDD2,
- (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
- VDD1_VGAIN_SEL_MASK);
- tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel);
+ tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD2,
+ VDD1_VGAIN_SEL_MASK,
+ dcdc_mult << VDD2_VGAIN_SEL_SHIFT);
+ tps65910_reg_write(pmic->mfd, TPS65910_VDD2_OP, vsel);
break;
case TPS65911_REG_VDDCTRL:
vsel = selector + 3;
- tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel);
+ tps65910_reg_write(pmic->mfd, TPS65911_VDDCTRL_OP, vsel);
}
return 0;
case TPS65910_REG_VAUX2:
case TPS65910_REG_VAUX33:
case TPS65910_REG_VMMC:
- return tps65910_modify_bits(pmic, reg,
- (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+ return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,
+ selector << LDO_SEL_SHIFT);
}
return -EINVAL;
case TPS65911_REG_LDO1:
case TPS65911_REG_LDO2:
case TPS65911_REG_LDO4:
- return tps65910_modify_bits(pmic, reg,
- (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+ return tps65910_reg_update_bits(pmic->mfd, reg, LDO1_SEL_MASK,
+ selector << LDO_SEL_SHIFT);
case TPS65911_REG_LDO3:
case TPS65911_REG_LDO5:
case TPS65911_REG_LDO6:
case TPS65911_REG_LDO7:
case TPS65911_REG_LDO8:
- return tps65910_modify_bits(pmic, reg,
- (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+ return tps65910_reg_update_bits(pmic->mfd, reg, LDO3_SEL_MASK,
+ selector << LDO_SEL_SHIFT);
case TPS65910_REG_VIO:
- return tps65910_modify_bits(pmic, reg,
- (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+ return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,
+ selector << LDO_SEL_SHIFT);
}
return -EINVAL;
return volt * 100 * mult;
}
-static int tps65910_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps65910_reg *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev), voltage;
-
- if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
- return -EINVAL;
-
- if (selector >= pmic->info[id]->n_voltages)
- return -EINVAL;
- else
- voltage = pmic->info[id]->voltage_table[selector] * 1000;
-
- return voltage;
-}
-
static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
{
struct tps65910_reg *pmic = rdev_get_drvdata(dev);
step_mv = 100;
break;
case TPS65910_REG_VIO:
- return pmic->info[id]->voltage_table[selector] * 1000;
+ return pmic->info[id]->voltage_table[selector];
default:
return -EINVAL;
}
return (LDO_MIN_VOLT + selector * step_mv) * 1000;
}
-static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
- unsigned int old_selector, unsigned int new_selector)
-{
- int id = rdev_get_id(dev);
- int old_volt, new_volt;
-
- old_volt = tps65910_list_voltage_dcdc(dev, old_selector);
- if (old_volt < 0)
- return old_volt;
-
- new_volt = tps65910_list_voltage_dcdc(dev, new_selector);
- if (new_volt < 0)
- return new_volt;
-
- /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
- switch (id) {
- case TPS65910_REG_VDD1:
- case TPS65910_REG_VDD2:
- return DIV_ROUND_UP(abs(old_volt - new_volt), 12500);
- case TPS65911_REG_VDDCTRL:
- return DIV_ROUND_UP(abs(old_volt - new_volt), 5000);
- }
- return -EINVAL;
-}
-
/* Regulator ops (except VRTC) */
static struct regulator_ops tps65910_ops_dcdc = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
.get_voltage_sel = tps65910_get_voltage_dcdc_sel,
.set_voltage_sel = tps65910_set_voltage_dcdc_sel,
- .set_voltage_time_sel = tps65910_set_voltage_dcdc_time_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.list_voltage = tps65910_list_voltage_dcdc,
};
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
.get_voltage = tps65910_get_voltage_vdd3,
- .list_voltage = tps65910_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
static struct regulator_ops tps65910_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
.get_voltage_sel = tps65910_get_voltage_sel,
.set_voltage_sel = tps65910_set_voltage_sel,
- .list_voltage = tps65910_list_voltage,
+ .list_voltage = regulator_list_voltage_table,
};
static struct regulator_ops tps65911_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .enable_time = tps65910_enable_time,
.set_mode = tps65910_set_mode,
.get_mode = tps65910_get_mode,
.get_voltage_sel = tps65911_get_voltage_sel,
(tps65910_chip_id(mfd) == TPS65911))) {
int op_reg_add = pmic->get_ctrl_reg(id) + 1;
int sr_reg_add = pmic->get_ctrl_reg(id) + 2;
- int opvsel = tps65910_reg_read_locked(pmic, op_reg_add);
- int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add);
+ int opvsel, srvsel;
+
+ ret = tps65910_reg_read(pmic->mfd, op_reg_add, &opvsel);
+ if (ret < 0)
+ return ret;
+ ret = tps65910_reg_read(pmic->mfd, sr_reg_add, &srvsel);
+ if (ret < 0)
+ return ret;
+
if (opvsel & VDD1_OP_CMD_MASK) {
u8 reg_val = srvsel & VDD1_OP_SEL_MASK;
- ret = tps65910_reg_write_locked(pmic, op_reg_add,
- reg_val);
+
+ ret = tps65910_reg_write(pmic->mfd, op_reg_add,
+ reg_val);
if (ret < 0) {
dev_err(mfd->dev,
"Error in configuring op register\n");
return ret;
}
}
- ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0);
+ ret = tps65910_reg_write(pmic->mfd, sr_reg_add, 0);
if (ret < 0) {
dev_err(mfd->dev, "Error in settting sr register\n");
return ret;
"ti,regulator-ext-sleep-control", &prop);
if (!ret)
pmic_plat_data->regulator_ext_sleep_control[idx] = prop;
+
}
return pmic_plat_data;
struct of_regulator_match **tps65910_reg_matches)
{
*tps65910_reg_matches = NULL;
- return 0;
+ return NULL;
}
#endif
return -ENOMEM;
}
- mutex_init(&pmic->mutex);
pmic->mfd = tps65910;
platform_set_drvdata(pdev, pmic);
pmic->info[i] = info;
pmic->desc[i].name = info->name;
+ pmic->desc[i].supply_name = info->vin_name;
pmic->desc[i].id = i;
pmic->desc[i].n_voltages = info->n_voltages;
+ pmic->desc[i].enable_time = info->enable_time_us;
if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
pmic->desc[i].ops = &tps65910_ops_dcdc;
pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE *
VDD1_2_NUM_VOLT_COARSE;
+ pmic->desc[i].ramp_delay = 12500;
} else if (i == TPS65910_REG_VDD3) {
- if (tps65910_chip_id(tps65910) == TPS65910)
+ if (tps65910_chip_id(tps65910) == TPS65910) {
pmic->desc[i].ops = &tps65910_ops_vdd3;
- else
+ pmic->desc[i].volt_table = info->voltage_table;
+ } else {
pmic->desc[i].ops = &tps65910_ops_dcdc;
+ pmic->desc[i].ramp_delay = 5000;
+ }
} else {
- if (tps65910_chip_id(tps65910) == TPS65910)
+ if (tps65910_chip_id(tps65910) == TPS65910) {
pmic->desc[i].ops = &tps65910_ops;
- else
+ pmic->desc[i].volt_table = info->voltage_table;
+ } else {
pmic->desc[i].ops = &tps65911_ops;
+ }
}
err = tps65910_set_ext_sleep_config(pmic, i,
u8 table_len;
const u16 *table;
- /* regulator specific turn-on delay */
- u16 delay;
-
/* State REMAP default configuration */
u8 remap;
return ret;
}
-static int twl4030reg_enable_time(struct regulator_dev *rdev)
-{
- struct twlreg_info *info = rdev_get_drvdata(rdev);
-
- return info->delay;
-}
-
-static int twl6030reg_enable_time(struct regulator_dev *rdev)
-{
- struct twlreg_info *info = rdev_get_drvdata(rdev);
-
- return info->delay;
-}
-
static int twl4030reg_disable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
- .enable_time = twl4030reg_enable_time,
.set_mode = twl4030reg_set_mode,
.get_voltage = twl6030coresmps_get_voltage,
};
-static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel)
{
- struct twlreg_info *info = rdev_get_drvdata(rdev);
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
- return ((info->min_mV + (index * 100)) * 1000);
+ switch (sel) {
+ case 0:
+ return 0;
+ case 1 ... 24:
+ /* Linear mapping from 00000001 to 00011000:
+ * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001)
+ */
+ return (info->min_mV + 100 * (sel - 1)) * 1000;
+ case 25 ... 30:
+ return -EINVAL;
+ case 31:
+ return 2750000;
+ default:
+ return -EINVAL;
+ }
}
static int
-twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned *selector)
+twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
- int vsel;
-
- if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV))
- return -EDOM;
-
- /*
- * Use the below formula to calculate vsel
- * mV = 1000mv + 100mv * (vsel - 1)
- */
- vsel = (min_uV/1000 - 1000)/100 + 1;
- *selector = vsel;
- return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
+ return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
+ selector);
}
-static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
+static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
- int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
- VREG_VOLTAGE);
-
- if (vsel < 0)
- return vsel;
+ int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE);
- /*
- * Use the below formula to calculate vsel
- * mV = 1000mv + 100mv * (vsel - 1)
- */
- return (1000 + (100 * (vsel - 1))) * 1000;
+ return vsel;
}
static struct regulator_ops twl6030ldo_ops = {
.list_voltage = twl6030ldo_list_voltage,
- .set_voltage = twl6030ldo_set_voltage,
- .get_voltage = twl6030ldo_get_voltage,
+ .set_voltage_sel = twl6030ldo_set_voltage_sel,
+ .get_voltage_sel = twl6030ldo_get_voltage_sel,
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
- .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
- .enable_time = twl4030reg_enable_time,
.set_mode = twl4030reg_set_mode,
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
- .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
- .enable_time = twl6030reg_enable_time,
.get_status = twl6030reg_get_status,
};
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
.is_enabled = twl6030reg_is_enabled,
- .enable_time = twl6030reg_enable_time,
.set_mode = twl6030reg_set_mode,
.id = num, \
.table_len = ARRAY_SIZE(label##_VSEL_table), \
.table = label##_VSEL_table, \
- .delay = turnon_delay, \
.remap = remap_conf, \
.desc = { \
.name = #label, \
.ops = &twl4030ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
+ .enable_time = turnon_delay, \
}, \
}
static struct twlreg_info TWL4030_INFO_##label = { \
.base = offset, \
.id = num, \
- .delay = turnon_delay, \
.remap = remap_conf, \
.desc = { \
.name = #label, \
.ops = &twl4030smps_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
+ .enable_time = turnon_delay, \
}, \
}
.desc = { \
.name = #label, \
.id = TWL6030_REG_##label, \
- .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
+ .n_voltages = 32, \
.ops = &twl6030ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.desc = { \
.name = #label, \
.id = TWL6025_REG_##label, \
- .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+ .n_voltages = 32, \
.ops = &twl6030ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.base = offset, \
.id = num, \
.min_mV = mVolts, \
- .delay = turnon_delay, \
.remap = remap_conf, \
.desc = { \
.name = #label, \
.ops = &operations, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
+ .enable_time = turnon_delay, \
}, \
}
#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
static struct twlreg_info TWLRES_INFO_##label = { \
.base = offset, \
- .delay = turnon_delay, \
.desc = { \
.name = #label, \
.id = TWL6030_REG_##label, \
.ops = &twl6030_fixed_resource, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
+ .enable_time = turnon_delay, \
}, \
}
#define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
#define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
#define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
-#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
#define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
static const struct of_device_id twl_of_match[] __devinitconst = {
TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
- TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
return -EINVAL;
}
-static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+static int wm831x_buckv_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
u16 vsel;
return 0;
}
-static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned vsel)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
struct wm831x *wm831x = dcdc->wm831x;
int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
- int vsel, ret;
-
- vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
- if (vsel < 0)
- return vsel;
-
- *selector = vsel;
+ int ret;
/* If this value is already set then do a GPIO update if we can */
if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
int vsel;
- vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+ vsel = wm831x_buckv_map_voltage(rdev, uV, uV);
if (vsel < 0)
return vsel;
}
static struct regulator_ops wm831x_buckv_ops = {
- .set_voltage = wm831x_buckv_set_voltage,
+ .set_voltage_sel = wm831x_buckv_set_voltage_sel,
.get_voltage_sel = wm831x_buckv_get_voltage_sel,
.list_voltage = wm831x_buckv_list_voltage,
+ .map_voltage = wm831x_buckv_map_voltage,
.set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
.set_current_limit = wm831x_buckv_set_current_limit,
.get_current_limit = wm831x_buckv_get_current_limit,
* BUCKP specifics
*/
-static int wm831x_buckp_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector <= WM831X_BUCKP_MAX_SELECTOR)
- return 850000 + (selector * 25000);
- else
- return -EINVAL;
-}
-
-static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV, int *selector)
+static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
struct wm831x *wm831x = dcdc->wm831x;
- u16 vsel;
-
- if (min_uV <= 34000000)
- vsel = (min_uV - 850000) / 25000;
- else
- return -EINVAL;
-
- if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV)
- return -EINVAL;
-
- *selector = vsel;
-
- return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_buckp_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
-
- return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV,
- selector);
-}
-
-static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
- int uV)
-{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
- unsigned selector;
+ int sel;
+
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
- return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
+ return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
}
static struct regulator_ops wm831x_buckp_ops = {
- .set_voltage = wm831x_buckp_set_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = wm831x_buckp_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
.is_enabled = regulator_is_enabled_regmap,
dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK;
dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
dcdc->desc.enable_mask = 1 << id;
+ dcdc->desc.min_uV = 850000;
+ dcdc->desc.uV_step = 25000;
config.dev = pdev->dev.parent;
if (pdata)
return -EINVAL;
}
-static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV,
- unsigned *selector)
+static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int vsel, ret;
+ int volt, vsel;
if (min_uV < 900000)
vsel = 0;
vsel = ((min_uV - 1700000) / 100000)
+ WM831X_GP_LDO_SELECTOR_LOW + 1;
- ret = wm831x_gp_ldo_list_voltage(rdev, vsel);
- if (ret < 0)
- return ret;
- if (ret < min_uV || ret > max_uV)
+ volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
+ if (volt < min_uV || volt > max_uV)
return -EINVAL;
- *selector = vsel;
-
- return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_LDO_ON_CONTROL;
-
- return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
- selector);
+ return vsel;
}
static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
int uV)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
- unsigned int selector;
+ struct wm831x *wm831x = ldo->wm831x;
+ int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
- return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+ sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
+
+ return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
}
static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
static struct regulator_ops wm831x_gp_ldo_ops = {
.list_voltage = wm831x_gp_ldo_list_voltage,
+ .map_voltage = wm831x_gp_ldo_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage = wm831x_gp_ldo_set_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
.get_mode = wm831x_gp_ldo_get_mode,
.set_mode = wm831x_gp_ldo_set_mode,
return -EINVAL;
}
-static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV,
- unsigned *selector)
+static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int vsel, ret;
+ int volt, vsel;
if (min_uV < 1000000)
vsel = 0;
vsel = ((min_uV - 1700000) / 100000)
+ WM831X_ALDO_SELECTOR_LOW + 1;
- ret = wm831x_aldo_list_voltage(rdev, vsel);
- if (ret < 0)
- return ret;
- if (ret < min_uV || ret > max_uV)
+ volt = wm831x_aldo_list_voltage(rdev, vsel);
+ if (volt < min_uV || volt > max_uV)
return -EINVAL;
- *selector = vsel;
-
- return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_aldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+ return vsel;
- return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV,
- selector);
}
static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
int uV)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
- unsigned int selector;
+ struct wm831x *wm831x = ldo->wm831x;
+ int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+
+ sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
- return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+ return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
}
static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
static struct regulator_ops wm831x_aldo_ops = {
.list_voltage = wm831x_aldo_list_voltage,
+ .map_voltage = wm831x_aldo_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage = wm831x_aldo_set_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
.get_mode = wm831x_aldo_get_mode,
.set_mode = wm831x_aldo_set_mode,
#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
-static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
- int reg,
- int min_uV, int max_uV,
- unsigned *selector)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = ldo->wm831x;
- int vsel, ret;
-
- vsel = (min_uV - 800000) / 50000;
-
- ret = regulator_list_voltage_linear(rdev, vsel);
- if (ret < 0)
- return ret;
- if (ret < min_uV || ret > max_uV)
- return -EINVAL;
-
- *selector = vsel;
-
- return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
-{
- struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
-
- return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
- selector);
-}
-
static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
int uV)
{
struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
- int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
- unsigned selector;
+ struct wm831x *wm831x = ldo->wm831x;
+ int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
+
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
- return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+ return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
}
static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
static struct regulator_ops wm831x_alive_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage = wm831x_alive_ldo_set_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
.get_status = wm831x_alive_ldo_get_status,
ldo->desc.enable_mask = 1 << id;
ldo->desc.min_uV = 800000;
ldo->desc.uV_step = 50000;
+ ldo->desc.enable_time = 1000;
config.dev = pdev->dev.parent;
if (pdata)
return -EINVAL;
}
-static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
-{
- if (val < 16)
- return (val * 50) + 900;
- else
- return ((val - 16) * 100) + 1800;
-
-}
-
-static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
-{
- if (mV < 1800)
- return (mV - 900) / 50;
- else
- return ((mV - 1800) / 100) + 16;
-}
-
-static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
-{
- return (val * 25) + 850;
-}
-
-static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
-{
- return (mV - 850) / 25;
-}
-
static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
int max_uA)
{
}
EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
-static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, dcdc = rdev_get_id(rdev), mV,
- min_mV = min_uV / 1000, max_mV = max_uV / 1000;
- u16 val;
-
- if (min_mV < 850 || min_mV > 4025)
- return -EINVAL;
- if (max_mV < 850 || max_mV > 4025)
- return -EINVAL;
-
- /* step size is 25mV */
- mV = (min_mV - 826) / 25;
- if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
- return -EINVAL;
- BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
-
- switch (dcdc) {
- case WM8350_DCDC_1:
- volt_reg = WM8350_DCDC1_CONTROL;
- break;
- case WM8350_DCDC_3:
- volt_reg = WM8350_DCDC3_CONTROL;
- break;
- case WM8350_DCDC_4:
- volt_reg = WM8350_DCDC4_CONTROL;
- break;
- case WM8350_DCDC_6:
- volt_reg = WM8350_DCDC6_CONTROL;
- break;
- case WM8350_DCDC_2:
- case WM8350_DCDC_5:
- default:
- return -EINVAL;
- }
-
- *selector = mV;
-
- /* all DCDCs have same mV bits */
- val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
- wm8350_reg_write(wm8350, volt_reg, val | mV);
- return 0;
-}
-
-static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, dcdc = rdev_get_id(rdev);
-
- switch (dcdc) {
- case WM8350_DCDC_1:
- volt_reg = WM8350_DCDC1_CONTROL;
- break;
- case WM8350_DCDC_3:
- volt_reg = WM8350_DCDC3_CONTROL;
- break;
- case WM8350_DCDC_4:
- volt_reg = WM8350_DCDC4_CONTROL;
- break;
- case WM8350_DCDC_6:
- volt_reg = WM8350_DCDC6_CONTROL;
- break;
- case WM8350_DCDC_2:
- case WM8350_DCDC_5:
- default:
- return -EINVAL;
- }
-
- /* all DCDCs have same mV bits */
- return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
-}
-
-static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector > WM8350_DCDC_MAX_VSEL)
- return -EINVAL;
- return wm8350_dcdc_val_to_mvolts(selector) * 1000;
-}
-
static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+ int sel, volt_reg, dcdc = rdev_get_id(rdev);
u16 val;
- dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
-
- if (mV && (mV < 850 || mV > 4025)) {
- dev_err(wm8350->dev,
- "DCDC%d suspend voltage %d mV out of range\n",
- dcdc, mV);
- return -EINVAL;
- }
- if (mV == 0)
- mV = 850;
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000);
switch (dcdc) {
case WM8350_DCDC_1:
return -EINVAL;
}
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return -EINVAL;
+
/* all DCDCs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
- wm8350_reg_write(wm8350, volt_reg,
- val | wm8350_dcdc_mvolts_to_val(mV));
+ wm8350_reg_write(wm8350, volt_reg, val | sel);
return 0;
}
return 0;
}
+static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector > WM8350_LDO1_VSEL_MASK)
+ return -EINVAL;
+
+ if (selector < 16)
+ return (selector * 50000) + 900000;
+ else
+ return ((selector - 16) * 100000) + 1800000;
+}
+
+static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ int volt, sel;
+ int min_mV = min_uV / 1000;
+ int max_mV = max_uV / 1000;
+
+ if (min_mV < 900 || min_mV > 3300)
+ return -EINVAL;
+ if (max_mV < 900 || max_mV > 3300)
+ return -EINVAL;
+
+ if (min_mV < 1800) /* step size is 50mV < 1800mV */
+ sel = DIV_ROUND_UP(min_uV - 900, 50);
+ else /* step size is 100mV > 1800mV */
+ sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
+
+ volt = wm8350_ldo_list_voltage(rdev, sel);
+ if (volt < min_uV || volt > max_uV)
+ return -EINVAL;
+
+ return sel;
+}
+
static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+ int sel, volt_reg, ldo = rdev_get_id(rdev);
u16 val;
- dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
-
- if (mV < 900 || mV > 3300) {
- dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
- ldo, mV);
- return -EINVAL;
- }
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, uV / 1000);
switch (ldo) {
case WM8350_LDO_1:
return -EINVAL;
}
+ sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+ if (sel < 0)
+ return -EINVAL;
+
/* all LDOs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
- wm8350_reg_write(wm8350, volt_reg,
- val | wm8350_ldo_mvolts_to_val(mV));
+ wm8350_reg_write(wm8350, volt_reg, val | sel);
return 0;
}
return 0;
}
-static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
- max_mV = max_uV / 1000;
- u16 val;
-
- if (min_mV < 900 || min_mV > 3300)
- return -EINVAL;
- if (max_mV < 900 || max_mV > 3300)
- return -EINVAL;
-
- if (min_mV < 1800) {
- /* step size is 50mV < 1800mV */
- mV = (min_mV - 851) / 50;
- if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
- return -EINVAL;
- BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
- } else {
- /* step size is 100mV > 1800mV */
- mV = ((min_mV - 1701) / 100) + 16;
- if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
- return -EINVAL;
- BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
- }
-
- switch (ldo) {
- case WM8350_LDO_1:
- volt_reg = WM8350_LDO1_CONTROL;
- break;
- case WM8350_LDO_2:
- volt_reg = WM8350_LDO2_CONTROL;
- break;
- case WM8350_LDO_3:
- volt_reg = WM8350_LDO3_CONTROL;
- break;
- case WM8350_LDO_4:
- volt_reg = WM8350_LDO4_CONTROL;
- break;
- default:
- return -EINVAL;
- }
-
- *selector = mV;
-
- /* all LDOs have same mV bits */
- val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
- wm8350_reg_write(wm8350, volt_reg, val | mV);
- return 0;
-}
-
-static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int volt_reg, ldo = rdev_get_id(rdev);
-
- switch (ldo) {
- case WM8350_LDO_1:
- volt_reg = WM8350_LDO1_CONTROL;
- break;
- case WM8350_LDO_2:
- volt_reg = WM8350_LDO2_CONTROL;
- break;
- case WM8350_LDO_3:
- volt_reg = WM8350_LDO3_CONTROL;
- break;
- case WM8350_LDO_4:
- volt_reg = WM8350_LDO4_CONTROL;
- break;
- default:
- return -EINVAL;
- }
-
- /* all LDOs have same mV bits */
- return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
-}
-
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector > WM8350_LDO1_VSEL_MASK)
- return -EINVAL;
- return wm8350_ldo_val_to_mvolts(selector) * 1000;
-}
-
int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
u16 stop, u16 fault)
{
}
EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
-static int wm8350_dcdc_enable(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int dcdc = rdev_get_id(rdev);
- u16 shift;
-
- if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
- return -EINVAL;
-
- shift = dcdc - WM8350_DCDC_1;
- wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
- return 0;
-}
-
-static int wm8350_dcdc_disable(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int dcdc = rdev_get_id(rdev);
- u16 shift;
-
- if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
- return -EINVAL;
-
- shift = dcdc - WM8350_DCDC_1;
- wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-
- return 0;
-}
-
-static int wm8350_ldo_enable(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int ldo = rdev_get_id(rdev);
- u16 shift;
-
- if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
- return -EINVAL;
-
- shift = (ldo - WM8350_LDO_1) + 8;
- wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
- return 0;
-}
-
-static int wm8350_ldo_disable(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int ldo = rdev_get_id(rdev);
- u16 shift;
-
- if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
- return -EINVAL;
-
- shift = (ldo - WM8350_LDO_1) + 8;
- wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
- return 0;
-}
-
static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
{
int reg = 0, ret;
return mode;
}
-static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int dcdc = rdev_get_id(rdev), shift;
-
- if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
- return -EINVAL;
-
- shift = dcdc - WM8350_DCDC_1;
- return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
- & (1 << shift);
-}
-
-static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
-{
- struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
- int ldo = rdev_get_id(rdev), shift;
-
- if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
- return -EINVAL;
-
- shift = (ldo - WM8350_LDO_1) + 8;
- return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
- & (1 << shift);
-}
-
static struct regulator_ops wm8350_dcdc_ops = {
- .set_voltage = wm8350_dcdc_set_voltage,
- .get_voltage_sel = wm8350_dcdc_get_voltage_sel,
- .list_voltage = wm8350_dcdc_list_voltage,
- .enable = wm8350_dcdc_enable,
- .disable = wm8350_dcdc_disable,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.get_mode = wm8350_dcdc_get_mode,
.set_mode = wm8350_dcdc_set_mode,
.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
- .is_enabled = wm8350_dcdc_is_enabled,
.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
};
static struct regulator_ops wm8350_dcdc2_5_ops = {
- .enable = wm8350_dcdc_enable,
- .disable = wm8350_dcdc_disable,
- .is_enabled = wm8350_dcdc_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
};
static struct regulator_ops wm8350_ldo_ops = {
- .set_voltage = wm8350_ldo_set_voltage,
- .get_voltage_sel = wm8350_ldo_get_voltage_sel,
+ .map_voltage = wm8350_ldo_map_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = wm8350_ldo_list_voltage,
- .enable = wm8350_ldo_enable,
- .disable = wm8350_ldo_disable,
- .is_enabled = wm8350_ldo_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.get_mode = wm8350_ldo_get_mode,
.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
.set_suspend_enable = wm8350_ldo_set_suspend_enable,
.irq = WM8350_IRQ_UV_DC1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+ .min_uV = 850000,
+ .uV_step = 25000,
+ .vsel_reg = WM8350_DCDC1_CONTROL,
+ .vsel_mask = WM8350_DC1_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC1_ENA,
.owner = THIS_MODULE,
},
{
.ops = &wm8350_dcdc2_5_ops,
.irq = WM8350_IRQ_UV_DC2,
.type = REGULATOR_VOLTAGE,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC2_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_DC3,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+ .min_uV = 850000,
+ .uV_step = 25000,
+ .vsel_reg = WM8350_DCDC3_CONTROL,
+ .vsel_mask = WM8350_DC3_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC3_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_DC4,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+ .min_uV = 850000,
+ .uV_step = 25000,
+ .vsel_reg = WM8350_DCDC4_CONTROL,
+ .vsel_mask = WM8350_DC4_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC4_ENA,
.owner = THIS_MODULE,
},
{
.ops = &wm8350_dcdc2_5_ops,
.irq = WM8350_IRQ_UV_DC5,
.type = REGULATOR_VOLTAGE,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC5_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_DC6,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+ .min_uV = 850000,
+ .uV_step = 25000,
+ .vsel_reg = WM8350_DCDC6_CONTROL,
+ .vsel_mask = WM8350_DC6_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_DC6_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_LDO1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+ .vsel_reg = WM8350_LDO1_CONTROL,
+ .vsel_mask = WM8350_LDO1_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_LDO1_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_LDO2,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+ .vsel_reg = WM8350_LDO2_CONTROL,
+ .vsel_mask = WM8350_LDO2_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_LDO2_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_LDO3,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+ .vsel_reg = WM8350_LDO3_CONTROL,
+ .vsel_mask = WM8350_LDO3_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_LDO3_ENA,
.owner = THIS_MODULE,
},
{
.irq = WM8350_IRQ_UV_LDO4,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+ .vsel_reg = WM8350_LDO4_CONTROL,
+ .vsel_mask = WM8350_LDO4_VSEL_MASK,
+ .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+ .enable_mask = WM8350_LDO4_ENA,
.owner = THIS_MODULE,
},
{
config.dev = &pdev->dev;
config.init_data = pdev->dev.platform_data;
config.driver_data = dev_get_drvdata(&pdev->dev);
+ config.regmap = wm8350->regmap;
/* register regulator */
rdev = regulator_register(&wm8350_reg[pdev->id], &config);
if (selector < 15)
return 900000 + (selector * 50000);
else
- return 1600000 + ((selector - 14) * 100000);
+ return 1700000 + ((selector - 15) * 100000);
}
static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
u16 val;
+ int volt;
if (min_uV < 900000 || min_uV > 3300000)
return -EINVAL;
- if (min_uV < 1700000) {
- /* Steps of 50mV from 900mV; */
+ if (min_uV < 1700000) /* Steps of 50mV from 900mV; */
val = DIV_ROUND_UP(min_uV - 900000, 50000);
+ else /* Steps of 100mV from 1700mV */
+ val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
- if ((val * 50000) + 900000 > max_uV)
- return -EINVAL;
- BUG_ON((val * 50000) + 900000 < min_uV);
- } else {
- /* Steps of 100mV from 1700mV */
- val = DIV_ROUND_UP(min_uV - 1700000, 100000);
-
- if ((val * 100000) + 1700000 > max_uV)
- return -EINVAL;
- BUG_ON((val * 100000) + 1700000 < min_uV);
-
- val += 0xf;
- }
+ volt = wm8400_ldo_list_voltage(dev, val);
+ if (volt < min_uV || volt > max_uV)
+ return -EINVAL;
return val;
}
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_mode = wm8400_dcdc_get_mode,
#include <linux/mfd/wm8994/pdata.h>
struct wm8994_ldo {
- int enable;
- bool is_enabled;
struct regulator_dev *regulator;
struct wm8994 *wm8994;
};
#define WM8994_LDO1_MAX_SELECTOR 0x7
#define WM8994_LDO2_MAX_SELECTOR 0x3
-static int wm8994_ldo_enable(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- /* If we have no soft control assume that the LDO is always enabled. */
- if (!ldo->enable)
- return 0;
-
- gpio_set_value_cansleep(ldo->enable, 1);
- ldo->is_enabled = true;
-
- return 0;
-}
-
-static int wm8994_ldo_disable(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- /* If we have no soft control assume that the LDO is always enabled. */
- if (!ldo->enable)
- return -EINVAL;
-
- gpio_set_value_cansleep(ldo->enable, 0);
- ldo->is_enabled = false;
-
- return 0;
-}
-
-static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- return ldo->is_enabled;
-}
-
-static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
-{
- /* 3ms is fairly conservative but this shouldn't be too performance
- * critical; can be tweaked per-system if required. */
- return 3000;
-}
-
-static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (selector > WM8994_LDO1_MAX_SELECTOR)
- return -EINVAL;
-
- return (selector * 100000) + 2400000;
-}
-
static struct regulator_ops wm8994_ldo1_ops = {
- .enable = wm8994_ldo_enable,
- .disable = wm8994_ldo_disable,
- .is_enabled = wm8994_ldo_is_enabled,
- .enable_time = wm8994_ldo_enable_time,
-
- .list_voltage = wm8994_ldo1_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
}
static struct regulator_ops wm8994_ldo2_ops = {
- .enable = wm8994_ldo_enable,
- .disable = wm8994_ldo_disable,
- .is_enabled = wm8994_ldo_is_enabled,
- .enable_time = wm8994_ldo_enable_time,
-
.list_voltage = wm8994_ldo2_list_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.vsel_reg = WM8994_LDO_1,
.vsel_mask = WM8994_LDO1_VSEL_MASK,
.ops = &wm8994_ldo1_ops,
+ .min_uV = 2400000,
+ .uV_step = 100000,
+ .enable_time = 3000,
.owner = THIS_MODULE,
},
{
.vsel_reg = WM8994_LDO_2,
.vsel_mask = WM8994_LDO2_VSEL_MASK,
.ops = &wm8994_ldo2_ops,
+ .enable_time = 3000,
.owner = THIS_MODULE,
},
};
ldo->wm8994 = wm8994;
- if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
- ldo->enable = pdata->ldo[id].enable;
-
- ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable");
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
- ret);
- goto err;
- }
- } else
- ldo->is_enabled = true;
-
config.dev = wm8994->dev;
config.driver_data = ldo;
config.regmap = wm8994->regmap;
- if (pdata)
+ if (pdata) {
config.init_data = pdata->ldo[id].init_data;
+ config.ena_gpio = pdata->ldo[id].enable;
+ }
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
id + 1, ret);
- goto err_gpio;
+ goto err;
}
platform_set_drvdata(pdev, ldo);
return 0;
-err_gpio:
- if (gpio_is_valid(ldo->enable))
- gpio_free(ldo->enable);
err:
return ret;
}
platform_set_drvdata(pdev, NULL);
regulator_unregister(ldo->regulator);
- if (gpio_is_valid(ldo->enable))
- gpio_free(ldo->enable);
return 0;
}
config REMOTEPROC
tristate
depends on EXPERIMENTAL
+ select FW_CONFIG
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
+ depends on EXPERIMENTAL
depends on ARCH_OMAP4
depends on OMAP_IOMMU
select REMOTEPROC
rpdev->id.name);
}
+/**
+ * __ept_release() - deallocate an rpmsg endpoint
+ * @kref: the ept's reference count
+ *
+ * This function deallocates an ept, and is invoked when its @kref refcount
+ * drops to zero.
+ *
+ * Never invoke this function directly!
+ */
+static void __ept_release(struct kref *kref)
+{
+ struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
+ refcount);
+ /*
+ * At this point no one holds a reference to ept anymore,
+ * so we can directly free it
+ */
+ kfree(ept);
+}
+
/* for more info, see below documentation of rpmsg_create_ept() */
static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb,
return NULL;
}
+ kref_init(&ept->refcount);
+ mutex_init(&ept->cb_lock);
+
ept->rpdev = rpdev;
ept->cb = cb;
ept->priv = priv;
idr_remove(&vrp->endpoints, request);
free_ept:
mutex_unlock(&vrp->endpoints_lock);
- kfree(ept);
+ kref_put(&ept->refcount, __ept_release);
return NULL;
}
static void
__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
{
+ /* make sure new inbound messages can't find this ept anymore */
mutex_lock(&vrp->endpoints_lock);
idr_remove(&vrp->endpoints, ept->addr);
mutex_unlock(&vrp->endpoints_lock);
- kfree(ept);
+ /* make sure in-flight inbound messages won't invoke cb anymore */
+ mutex_lock(&ept->cb_lock);
+ ept->cb = NULL;
+ mutex_unlock(&ept->cb_lock);
+
+ kref_put(&ept->refcount, __ept_release);
}
/**
/* use the dst addr to fetch the callback of the appropriate user */
mutex_lock(&vrp->endpoints_lock);
+
ept = idr_find(&vrp->endpoints, msg->dst);
+
+ /* let's make sure no one deallocates ept while we use it */
+ if (ept)
+ kref_get(&ept->refcount);
+
mutex_unlock(&vrp->endpoints_lock);
- if (ept && ept->cb)
- ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src);
- else
+ if (ept) {
+ /* make sure ept->cb doesn't go away while we use it */
+ mutex_lock(&ept->cb_lock);
+
+ if (ept->cb)
+ ept->cb(ept->rpdev, msg->data, msg->len, ept->priv,
+ msg->src);
+
+ mutex_unlock(&ept->cb_lock);
+
+ /* farewell, ept, we don't need you anymore */
+ kref_put(&ept->refcount, __ept_release);
+ } else
dev_warn(dev, "msg received with no recepient\n");
/* publish the real size of the buffer */
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/delay.h>
+#include <linux/of.h>
#define AB8500_RTC_SOFF_STAT_REG 0x00
#define AB8500_RTC_CC_CONF_REG 0x01
}
err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
- IRQF_NO_SUSPEND, "ab8500-rtc", rtc);
+ IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc);
if (err < 0) {
rtc_device_unregister(rtc);
return err;
platform_set_drvdata(pdev, rtc);
-
err = ab8500_sysfs_rtc_register(&pdev->dev);
if (err) {
dev_err(&pdev->dev, "sysfs RTC failed to register\n");
return 0;
}
+static const struct of_device_id ab8500_rtc_match[] = {
+ { .compatible = "stericsson,ab8500-rtc", },
+ {}
+};
+
static struct platform_driver ab8500_rtc_driver = {
.driver = {
.name = "ab8500-rtc",
.owner = THIS_MODULE,
+ .of_match_table = ab8500_rtc_match,
},
.probe = ab8500_rtc_probe,
.remove = __devexit_p(ab8500_rtc_remove),
struct platform_device *pdev = dev_id;
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long flags;
u32 status;
u32 events = 0;
- spin_lock_irq(&pdata->rtc->irq_lock);
+ spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
/* clear interrupt sources */
writew(status, ioaddr + RTC_RTCISR);
events |= (RTC_PF | RTC_IRQF);
rtc_update_irq(pdata->rtc, 1, events);
- spin_unlock_irq(&pdata->rtc->irq_lock);
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
return IRQ_HANDLED;
}
clk_disable(config->clk);
clk_put(config->clk);
iounmap(config->ioaddr);
- kfree(config);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
rtc_device_unregister(config->rtc);
+ kfree(config);
return 0;
}
}
ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&rtc->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
- memcpy(&resp->ending_fis[0], r+16, 24);
+ memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE);
ts->buf_valid_size = sizeof(*resp);
}
}
struct pci_dev *pcidev;
struct net_device *netdev;
void __iomem *regview;
+ resource_size_t reg_base;
u32 age;
unsigned long cnic_dev_type;
goto arm_cq;
}
- reg_base = ep->hba->netdev->base_addr;
if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
(ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
/* 5709 device in normal node and 5706/5708 devices */
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
- ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
+ ep->qp.ctx_base = ioremap_nocache(ep->hba->reg_base + reg_off,
MB_KERNEL_CTX_SIZE);
if (!ep->qp.ctx_base)
return -ENOMEM;
bnx2i_identify_device(hba);
bnx2i_setup_host_queue_size(hba, shost);
+ hba->reg_base = pci_resource_start(hba->pcidev, 0);
if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
- hba->regview = ioremap_nocache(hba->netdev->base_addr,
- BNX2_MQ_CONFIG2);
+ hba->regview = pci_iomap(hba->pcidev, 0, BNX2_MQ_CONFIG2);
if (!hba->regview)
goto ioreg_map_err;
} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
- hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
+ hba->regview = pci_iomap(hba->pcidev, 0, 4096);
if (!hba->regview)
goto ioreg_map_err;
}
bnx2i_free_mp_bdt(hba);
mp_bdt_mem_err:
if (hba->regview) {
- iounmap(hba->regview);
+ pci_iounmap(hba->pcidev, hba->regview);
hba->regview = NULL;
}
ioreg_map_err:
pci_dev_put(hba->pcidev);
if (hba->regview) {
- iounmap(hba->regview);
+ pci_iounmap(hba->pcidev, hba->regview);
hba->regview = NULL;
}
bnx2i_free_mp_bdt(hba);
if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
((stat->stat == SAM_STAT_CHECK_CONDITION &&
dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
- ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
+ memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE);
if (!link->sactive) {
- qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+ qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
} else {
- link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+ link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
if (unlikely(link->eh_info.err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
}
qc->flags |= ATA_QCFLAG_FAILED;
}
- dev->sata_dev.tf.feature = 0x04; /* status err */
- dev->sata_dev.tf.command = ATA_ERR;
+ dev->sata_dev.fis[3] = 0x04; /* status err */
+ dev->sata_dev.fis[2] = ATA_ERR;
}
}
{
struct domain_device *dev = qc->ap->private_data;
- memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf));
+ ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf);
return true;
}
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt *tgt = ha->tgt.qla_tgt;
- int reason_code;
+ int login_code;
ql_dbg(ql_dbg_tgt, vha, 0xe039,
"scsi(%ld): ha state %d init_done %d oper_mode %d topo %d\n",
{
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03b,
"qla_target(%d): Async LOOP_UP occured "
- "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx,
- le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
- le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+ "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx,
+ le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+ le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
if (tgt->link_reinit_iocb_pending) {
qlt_send_notify_ack(vha, (void *)&tgt->link_reinit_iocb,
0, 0, 0, 0, 0, 0);
case MBA_RSCN_UPDATE:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03c,
"qla_target(%d): Async event %#x occured "
- "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx, code,
- le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
- le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+ "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx, code,
+ le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+ le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
break;
case MBA_PORT_UPDATE:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03d,
"qla_target(%d): Port update async event %#x "
- "occured: updating the ports database (m[1]=%x, m[2]=%x, "
- "m[3]=%x, m[4]=%x)", vha->vp_idx, code,
- le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
- le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
- reason_code = le16_to_cpu(mailbox[2]);
- if (reason_code == 0x4)
+ "occured: updating the ports database (m[0]=%x, m[1]=%x, "
+ "m[2]=%x, m[3]=%x)", vha->vp_idx, code,
+ le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+ le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
+
+ login_code = le16_to_cpu(mailbox[2]);
+ if (login_code == 0x4)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03e,
"Async MB 2: Got PLOGI Complete\n");
- else if (reason_code == 0x7)
+ else if (login_code == 0x7)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03f,
"Async MB 2: Port Logged Out\n");
break;
default:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf040,
"qla_target(%d): Async event %#x occured: "
- "ignore (m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx,
- code, le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
- le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+ "ignore (m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx,
+ code, le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+ le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
break;
}
struct ft_tport *tport;
int i;
- tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
+ tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP],
+ lockdep_is_held(&ft_lport_lock));
if (tport && tport->tpg)
return tport;
}
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW
-void __init udbg_init_debug_opal(void)
+void __init udbg_init_debug_opal_raw(void)
{
u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO;
hvc_opal_privs[index] = &hvc_opal_boot_priv;
goto retry;
}
if (!desc->reslength) { /* zero length read */
+ dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
+ clear_bit(WDM_READ, &desc->flags);
spin_unlock_irq(&desc->iuspin);
goto retry;
}
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm);
-/* Is a USB 3.0 port in the Inactive state? */
-static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
+/* Is a USB 3.0 port in the Inactive or Complinance Mode state?
+ * Port worm reset is required to recover
+ */
+static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)
{
return hub_is_superspeed(hub->hdev) &&
- (portstatus & USB_PORT_STAT_LINK_STATE) ==
- USB_SS_PORT_LS_SS_INACTIVE;
+ (((portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_SS_INACTIVE) ||
+ ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_COMP_MOD)) ;
}
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
*
* See https://bugzilla.kernel.org/show_bug.cgi?id=41752
*/
- if (hub_port_inactive(hub, portstatus)) {
+ if (hub_port_warm_reset_required(hub, portstatus)) {
int ret;
if ((portchange & USB_PORT_STAT_C_CONNECTION))
/* Warm reset a USB3 protocol port if it's in
* SS.Inactive state.
*/
- if (hub_is_superspeed(hub->hdev) &&
- (portstatus & USB_PORT_STAT_LINK_STATE)
- == USB_SS_PORT_LS_SS_INACTIVE) {
+ if (hub_port_warm_reset_required(hub, portstatus)) {
dev_dbg(hub_dev, "warm reset port %d\n", i);
hub_port_reset(hub, i, NULL,
HUB_BH_RESET_TIME, true);
}
}
+ /* Hold PHYs in reset while initializing EHCI controller */
if (pdata->phy_reset) {
if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_request_one(pdata->reset_gpio_port[0],
- GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+ gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_request_one(pdata->reset_gpio_port[1],
- GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+ gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
/* Hold the PHY in RESET for enough time till DIR is high */
udelay(10);
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
ehci_reset(omap_ehci);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(dev, "failed to add hcd with err %d\n", ret);
+ goto err_add_hcd;
+ }
if (pdata->phy_reset) {
/* Hold the PHY in RESET for enough time till
gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret) {
- dev_err(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
- }
-
/* root ports should always stay powered */
ehci_port_power(omap_ehci, 1);
}
}
+/* Updates Link Status for super Speed port */
+static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+{
+ u32 pls = status_reg & PORT_PLS_MASK;
+
+ /* resume state is a xHCI internal state.
+ * Do not report it to usb core.
+ */
+ if (pls == XDEV_RESUME)
+ return;
+
+ /* When the CAS bit is set then warm reset
+ * should be performed on port
+ */
+ if (status_reg & PORT_CAS) {
+ /* The CAS bit can be set while the port is
+ * in any link state.
+ * Only roothubs have CAS bit, so we
+ * pretend to be in compliance mode
+ * unless we're already in compliance
+ * or the inactive state.
+ */
+ if (pls != USB_SS_PORT_LS_COMP_MOD &&
+ pls != USB_SS_PORT_LS_SS_INACTIVE) {
+ pls = USB_SS_PORT_LS_COMP_MOD;
+ }
+ /* Return also connection bit -
+ * hub state machine resets port
+ * when this bit is set.
+ */
+ pls |= USB_PORT_STAT_CONNECTION;
+ }
+ /* update status field */
+ *status |= pls;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
else
status |= USB_PORT_STAT_POWER;
}
- /* Port Link State */
+ /* Update Port Link State for super speed ports*/
if (hcd->speed == HCD_USB3) {
- /* resume state is a xHCI internal state.
- * Do not report it to usb core.
- */
- if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
- status |= (temp & PORT_PLS_MASK);
+ xhci_hub_report_link_state(&status, temp);
}
if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
num_trbs_free_temp = ep_ring->num_trbs_free;
dequeue_temp = ep_ring->dequeue;
+ /* If we get two back-to-back stalls, and the first stalled transfer
+ * ends just before a link TRB, the dequeue pointer will be left on
+ * the link TRB by the code in the while loop. So we have to update
+ * the dequeue pointer one segment further, or we'll jump off
+ * the segment into la-la-land.
+ */
+ if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
+ ep_ring->deq_seg = ep_ring->deq_seg->next;
+ ep_ring->dequeue = ep_ring->deq_seg->trbs;
+ }
+
while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
/* We have more usable TRBs */
ep_ring->num_trbs_free++;
#define PORT_PLC (1 << 22)
/* port configure error change - port failed to configure its link partner */
#define PORT_CEC (1 << 23)
-/* bit 24 reserved */
+/* Cold Attach Status - xHC can set this bit to report device attached during
+ * Sx state. Warm port reset should be perfomed to clear this bit and move port
+ * to connected state.
+ */
+#define PORT_CAS (1 << 24)
/* wake on connect (enable) */
#define PORT_WKCONN_E (1 << 25)
/* wake on disconnect (enable) */
metro_priv->throttled = 0;
spin_unlock_irqrestore(&metro_priv->lock, flags);
- /*
- * Force low_latency on so that our tty_push actually forces the data
- * through, otherwise it is scheduled, and with high data rates (like
- * with OHCI) data can get lost.
- */
- if (tty)
- tty->low_latency = 1;
-
/* Clear the urb pipe. */
usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
/* MediaTek products */
#define MEDIATEK_VENDOR_ID 0x0e8d
+#define MEDIATEK_PRODUCT_DC_1COM 0x00a0
+#define MEDIATEK_PRODUCT_DC_4COM 0x00a5
+#define MEDIATEK_PRODUCT_DC_5COM 0x00a4
+#define MEDIATEK_PRODUCT_7208_1COM 0x7101
+#define MEDIATEK_PRODUCT_7208_2COM 0x7102
+#define MEDIATEK_PRODUCT_FP_1COM 0x0003
+#define MEDIATEK_PRODUCT_FP_2COM 0x0023
+#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043
+#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033
/* Cellient products */
#define CELLIENT_VENDOR_ID 0x2692
.reserved = BIT(1),
};
+static const struct option_blacklist_info net_intf2_blacklist = {
+ .reserved = BIT(2),
+};
+
static const struct option_blacklist_info net_intf3_blacklist = {
.reserved = BIT(3),
};
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
{ } /* Terminating entry */
};
#include <linux/io.h>
#include <linux/device.h>
#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
#include <video/omapdss.h>
#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
/* PLATFORM DEVICE */
+static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
+{
+ DSSDBG("pm notif %lu\n", v);
+
+ switch (v) {
+ case PM_SUSPEND_PREPARE:
+ DSSDBG("suspending displays\n");
+ return dss_suspend_all_devices();
+
+ case PM_POST_SUSPEND:
+ DSSDBG("resuming displays\n");
+ return dss_resume_all_devices();
+
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block omap_dss_pm_notif_block = {
+ .notifier_call = omap_dss_pm_notif,
+};
+
static int __init omap_dss_probe(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
else if (pdata->default_device)
core.default_display_name = pdata->default_device->name;
+ register_pm_notifier(&omap_dss_pm_notif_block);
+
return 0;
err_debugfs:
static int omap_dss_remove(struct platform_device *pdev)
{
+ unregister_pm_notifier(&omap_dss_pm_notif_block);
+
dss_uninitialize_debugfs();
dss_uninit_overlays(pdev);
dss_disable_all_devices();
}
-static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
-{
- DSSDBG("suspend %d\n", state.event);
-
- return dss_suspend_all_devices();
-}
-
-static int omap_dss_resume(struct platform_device *pdev)
-{
- DSSDBG("resume\n");
-
- return dss_resume_all_devices();
-}
-
static struct platform_driver omap_dss_driver = {
.remove = omap_dss_remove,
.shutdown = omap_dss_shutdown,
- .suspend = omap_dss_suspend,
- .resume = omap_dss_resume,
.driver = {
.name = "omapdss",
.owner = THIS_MODULE,
DSSDBG("dispc_runtime_put\n");
r = pm_runtime_put_sync(&dispc.pdev->dev);
- WARN_ON(r < 0);
+ WARN_ON(r < 0 && r != -ENOSYS);
}
static inline bool dispc_mgr_is_lcd(enum omap_channel channel)
DSSDBG("dsi_runtime_put\n");
r = pm_runtime_put_sync(&dsi->pdev->dev);
- WARN_ON(r < 0);
+ WARN_ON(r < 0 && r != -ENOSYS);
}
/* source clock for DSI PLL. this could also be PCLKFREE */
DSSDBG("dss_runtime_put\n");
r = pm_runtime_put_sync(&dss.pdev->dev);
- WARN_ON(r < 0 && r != -EBUSY);
+ WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
}
/* DEBUGFS */
DSSDBG("hdmi_runtime_put\n");
r = pm_runtime_put_sync(&hdmi.pdev->dev);
- WARN_ON(r < 0);
+ WARN_ON(r < 0 && r != -ENOSYS);
}
static int __init hdmi_init_display(struct omap_dss_device *dssdev)
DSSDBG("rfbi_runtime_put\n");
r = pm_runtime_put_sync(&rfbi.pdev->dev);
- WARN_ON(r < 0);
+ WARN_ON(r < 0 && r != -ENOSYS);
}
void rfbi_bus_lock(void)
DSSDBG("venc_runtime_put\n");
r = pm_runtime_put_sync(&venc.pdev->dev);
- WARN_ON(r < 0);
+ WARN_ON(r < 0 && r != -ENOSYS);
}
static const struct venc_config *venc_timings_to_config(
struct task_struct *thread;
/* Waiting for host to ack the pages we released. */
- struct completion acked;
+ wait_queue_head_t acked;
/* Number of balloon pages we've told the Host we're not using. */
unsigned int num_pages;
static void balloon_ack(struct virtqueue *vq)
{
- struct virtio_balloon *vb;
- unsigned int len;
+ struct virtio_balloon *vb = vq->vdev->priv;
- vb = virtqueue_get_buf(vq, &len);
- if (vb)
- complete(&vb->acked);
+ wake_up(&vb->acked);
}
static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
{
struct scatterlist sg;
+ unsigned int len;
sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
- init_completion(&vb->acked);
-
/* We should always be able to add one buffer to an empty queue. */
if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
BUG();
virtqueue_kick(vq);
/* When host has read buffer, this completes via balloon_ack */
- wait_for_completion(&vb->acked);
+ wait_event(vb->acked, virtqueue_get_buf(vq, &len));
}
static void set_page_pfns(u32 pfns[], struct page *page)
*/
static void stats_request(struct virtqueue *vq)
{
- struct virtio_balloon *vb;
- unsigned int len;
+ struct virtio_balloon *vb = vq->vdev->priv;
- vb = virtqueue_get_buf(vq, &len);
- if (!vb)
- return;
vb->need_stats_update = 1;
wake_up(&vb->config_change);
}
{
struct virtqueue *vq;
struct scatterlist sg;
+ unsigned int len;
vb->need_stats_update = 0;
update_balloon_stats(vb);
vq = vb->stats_vq;
+ if (!virtqueue_get_buf(vq, &len))
+ return;
sg_init_one(&sg, vb->stats, sizeof(vb->stats));
if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
BUG();
INIT_LIST_HEAD(&vb->pages);
vb->num_pages = 0;
init_waitqueue_head(&vb->config_change);
+ init_waitqueue_head(&vb->acked);
vb->vdev = vdev;
vb->need_stats_update = 0;
goto out;
eb = path->nodes[level];
- if (!eb) {
- WARN_ON(1);
- ret = 1;
- goto out;
+ while (!eb) {
+ if (!level) {
+ WARN_ON(1);
+ ret = 1;
+ goto out;
+ }
+ level--;
+ eb = path->nodes[level];
}
ret = add_all_parents(root, path, parents, level, &ref->key_for_search,
}
ret = __add_delayed_refs(head, delayed_ref_seq,
&prefs_delayed);
+ mutex_unlock(&head->mutex);
if (ret) {
spin_unlock(&delayed_refs->lock);
goto out;
}
out:
- if (head)
- mutex_unlock(&head->mutex);
btrfs_free_path(path);
while (!list_empty(&prefs)) {
ref = list_first_entry(&prefs, struct __prelim_ref, list);
if (!looped && !tm)
return 0;
/*
- * we must have key remove operations in the log before the
- * replace operation.
+ * if there are no tree operation for the oldest root, we simply
+ * return it. this should only happen if that (old) root is at
+ * level 0.
*/
- BUG_ON(!tm);
+ if (!tm)
+ break;
+ /*
+ * if there's an operation that's not a root replacement, we
+ * found the oldest version of our root. normally, we'll find a
+ * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here.
+ */
if (tm->op != MOD_LOG_ROOT_REPLACE)
break;
tm->generation);
break;
case MOD_LOG_KEY_ADD:
- if (tm->slot != n - 1) {
- o_dst = btrfs_node_key_ptr_offset(tm->slot);
- o_src = btrfs_node_key_ptr_offset(tm->slot + 1);
- memmove_extent_buffer(eb, o_dst, o_src, p_size);
- }
+ /* if a move operation is needed it's in the log */
n--;
break;
case MOD_LOG_MOVE_KEYS:
}
tm = tree_mod_log_search(root->fs_info, logical, time_seq);
- /*
- * there was an item in the log when __tree_mod_log_oldest_root
- * returned. this one must not go away, because the time_seq passed to
- * us must be blocking its removal.
- */
- BUG_ON(!tm);
-
if (old_root)
- eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT,
- root->nodesize);
+ eb = alloc_dummy_extent_buffer(logical, root->nodesize);
else
eb = btrfs_clone_extent_buffer(root->node);
btrfs_tree_read_unlock(root->node);
btrfs_set_header_level(eb, old_root->level);
btrfs_set_header_generation(eb, old_generation);
}
- __tree_mod_log_rewind(eb, time_seq, tm);
+ if (tm)
+ __tree_mod_log_rewind(eb, time_seq, tm);
+ else
+ WARN_ON(btrfs_header_level(eb) != 0);
extent_buffer_get(eb);
return eb;
static void insert_ptr(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_disk_key *key, u64 bytenr,
- int slot, int level, int tree_mod_log)
+ int slot, int level)
{
struct extent_buffer *lower;
int nritems;
BUG_ON(slot > nritems);
BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root));
if (slot != nritems) {
- if (tree_mod_log && level)
+ if (level)
tree_mod_log_eb_move(root->fs_info, lower, slot + 1,
slot, nritems - slot);
memmove_extent_buffer(lower,
btrfs_node_key_ptr_offset(slot),
(nritems - slot) * sizeof(struct btrfs_key_ptr));
}
- if (tree_mod_log && level) {
+ if (level) {
ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
MOD_LOG_KEY_ADD);
BUG_ON(ret < 0);
btrfs_mark_buffer_dirty(split);
insert_ptr(trans, root, path, &disk_key, split->start,
- path->slots[level + 1] + 1, level + 1, 1);
+ path->slots[level + 1] + 1, level + 1);
if (path->slots[level] >= mid) {
path->slots[level] -= mid;
btrfs_set_header_nritems(l, mid);
btrfs_item_key(right, &disk_key, 0);
insert_ptr(trans, root, path, &disk_key, right->start,
- path->slots[1] + 1, 1, 0);
+ path->slots[1] + 1, 1);
btrfs_mark_buffer_dirty(right);
btrfs_mark_buffer_dirty(l);
if (mid <= slot) {
btrfs_set_header_nritems(right, 0);
insert_ptr(trans, root, path, &disk_key, right->start,
- path->slots[1] + 1, 1, 0);
+ path->slots[1] + 1, 1);
btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
} else {
btrfs_set_header_nritems(right, 0);
insert_ptr(trans, root, path, &disk_key, right->start,
- path->slots[1], 1, 0);
+ path->slots[1], 1);
btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
if (!path->skip_locking) {
ret = btrfs_try_tree_read_lock(next);
+ if (!ret && time_seq) {
+ /*
+ * If we don't get the lock, we may be racing
+ * with push_leaf_left, holding that lock while
+ * itself waiting for the leaf we've currently
+ * locked. To solve this situation, we give up
+ * on our lock and cycle.
+ */
+ btrfs_release_path(path);
+ cond_resched();
+ goto again;
+ }
if (!ret) {
btrfs_set_path_blocking(path);
btrfs_tree_read_lock(next);
BTRFS_CSUM_TREE_OBJECTID, csum_root);
if (ret)
goto recovery_tree_root;
-
csum_root->track_dirty = 1;
fs_info->generation = generation;
fs_info->last_trans_committed = generation;
+ ret = btrfs_recover_balance(fs_info);
+ if (ret) {
+ printk(KERN_WARNING "btrfs: failed to recover balance\n");
+ goto fail_block_groups;
+ }
+
ret = btrfs_init_dev_stats(fs_info);
if (ret) {
printk(KERN_ERR "btrfs: failed to init dev_stats: %d\n",
goto fail_trans_kthread;
}
- if (!(sb->s_flags & MS_RDONLY)) {
- down_read(&fs_info->cleanup_work_sem);
- err = btrfs_orphan_cleanup(fs_info->fs_root);
- if (!err)
- err = btrfs_orphan_cleanup(fs_info->tree_root);
- up_read(&fs_info->cleanup_work_sem);
+ if (sb->s_flags & MS_RDONLY)
+ return 0;
- if (!err)
- err = btrfs_recover_balance(fs_info->tree_root);
+ down_read(&fs_info->cleanup_work_sem);
+ if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
+ (ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
+ up_read(&fs_info->cleanup_work_sem);
+ close_ctree(tree_root);
+ return ret;
+ }
+ up_read(&fs_info->cleanup_work_sem);
- if (err) {
- close_ctree(tree_root);
- return err;
- }
+ ret = btrfs_resume_balance_async(fs_info);
+ if (ret) {
+ printk(KERN_WARNING "btrfs: failed to resume balance\n");
+ close_ctree(tree_root);
+ return ret;
}
return 0;
return count;
}
-
static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
- unsigned long num_refs)
+ unsigned long num_refs,
+ struct list_head *first_seq)
{
- struct list_head *first_seq = delayed_refs->seq_head.next;
-
spin_unlock(&delayed_refs->lock);
pr_debug("waiting for more refs (num %ld, first %p)\n",
num_refs, first_seq);
struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_delayed_ref_node *ref;
struct list_head cluster;
+ struct list_head *first_seq = NULL;
int ret;
u64 delayed_start;
int run_all = count == (unsigned long)-1;
*/
consider_waiting = 1;
num_refs = delayed_refs->num_entries;
+ first_seq = root->fs_info->tree_mod_seq_list.next;
} else {
- wait_for_more_refs(delayed_refs, num_refs);
+ wait_for_more_refs(delayed_refs,
+ num_refs, first_seq);
/*
* after waiting, things have changed. we
* dropped the lock and someone else might have
writepage_t writepage, void *data,
void (*flush_fn)(void *))
{
+ struct inode *inode = mapping->host;
int ret = 0;
int done = 0;
int nr_to_write_done = 0;
int scanned = 0;
int tag;
+ /*
+ * We have to hold onto the inode so that ordered extents can do their
+ * work when the IO finishes. The alternative to this is failing to add
+ * an ordered extent if the igrab() fails there and that is a huge pain
+ * to deal with, so instead just hold onto the inode throughout the
+ * writepages operation. If it fails here we are freeing up the inode
+ * anyway and we'd rather not waste our time writing out stuff that is
+ * going to be truncated anyway.
+ */
+ if (!igrab(inode))
+ return 0;
+
pagevec_init(&pvec, 0);
if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */
index = 0;
goto retry;
}
+ btrfs_add_delayed_iput(inode);
return ret;
}
loff_t *ppos, size_t count, size_t ocount)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = fdentry(file)->d_inode;
struct iov_iter i;
ssize_t written;
ssize_t written_buffered;
written = generic_file_direct_write(iocb, iov, &nr_segs, pos, ppos,
count, ocount);
- /*
- * the generic O_DIRECT will update in-memory i_size after the
- * DIOs are done. But our endio handlers that update the on
- * disk i_size never update past the in memory i_size. So we
- * need one more update here to catch any additions to the
- * file
- */
- if (inode->i_size != BTRFS_I(inode)->disk_i_size) {
- btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
- mark_inode_dirty(inode);
- }
-
if (written < 0 || written == count)
return written;
end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1;
/*
- * XXX - this can go away after a few releases.
- *
- * since the only user of btrfs_remove_free_space is the tree logging
- * stuff, and the only way to test that is under crash conditions, we
- * want to have this debug stuff here just in case somethings not
- * working. Search the bitmap for the space we are trying to use to
- * make sure its actually there. If its not there then we need to stop
- * because something has gone wrong.
+ * We need to search for bits in this bitmap. We could only cover some
+ * of the extent in this bitmap thanks to how we add space, so we need
+ * to search for as much as it as we can and clear that amount, and then
+ * go searching for the next bit.
*/
search_start = *offset;
- search_bytes = *bytes;
+ search_bytes = ctl->unit;
search_bytes = min(search_bytes, end - search_start + 1);
ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
BUG_ON(ret < 0 || search_start != *offset);
- if (*offset > bitmap_info->offset && *offset + *bytes > end) {
- bitmap_clear_bits(ctl, bitmap_info, *offset, end - *offset + 1);
- *bytes -= end - *offset + 1;
- *offset = end + 1;
- } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
- bitmap_clear_bits(ctl, bitmap_info, *offset, *bytes);
- *bytes = 0;
- }
+ /* We may have found more bits than what we need */
+ search_bytes = min(search_bytes, *bytes);
+
+ /* Cannot clear past the end of the bitmap */
+ search_bytes = min(search_bytes, end - search_start + 1);
+
+ bitmap_clear_bits(ctl, bitmap_info, search_start, search_bytes);
+ *offset += search_bytes;
+ *bytes -= search_bytes;
if (*bytes) {
struct rb_node *next = rb_next(&bitmap_info->offset_index);
* everything over again.
*/
search_start = *offset;
- search_bytes = *bytes;
+ search_bytes = ctl->unit;
ret = search_bitmap(ctl, bitmap_info, &search_start,
&search_bytes);
if (ret < 0 || search_start != *offset)
{
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
struct btrfs_free_space *info;
- struct btrfs_free_space *next_info = NULL;
int ret = 0;
spin_lock(&ctl->tree_lock);
again:
+ if (!bytes)
+ goto out_lock;
+
info = tree_search_offset(ctl, offset, 0, 0);
if (!info) {
/*
}
}
- if (info->bytes < bytes && rb_next(&info->offset_index)) {
- u64 end;
- next_info = rb_entry(rb_next(&info->offset_index),
- struct btrfs_free_space,
- offset_index);
-
- if (next_info->bitmap)
- end = next_info->offset +
- BITS_PER_BITMAP * ctl->unit - 1;
- else
- end = next_info->offset + next_info->bytes;
-
- if (next_info->bytes < bytes ||
- next_info->offset > offset || offset > end) {
- printk(KERN_CRIT "Found free space at %llu, size %llu,"
- " trying to use %llu\n",
- (unsigned long long)info->offset,
- (unsigned long long)info->bytes,
- (unsigned long long)bytes);
- WARN_ON(1);
- ret = -EINVAL;
- goto out_lock;
- }
-
- info = next_info;
- }
-
- if (info->bytes == bytes) {
+ if (!info->bitmap) {
unlink_free_space(ctl, info);
- if (info->bitmap) {
- kfree(info->bitmap);
- ctl->total_bitmaps--;
- }
- kmem_cache_free(btrfs_free_space_cachep, info);
- ret = 0;
- goto out_lock;
- }
-
- if (!info->bitmap && info->offset == offset) {
- unlink_free_space(ctl, info);
- info->offset += bytes;
- info->bytes -= bytes;
- ret = link_free_space(ctl, info);
- WARN_ON(ret);
- goto out_lock;
- }
+ if (offset == info->offset) {
+ u64 to_free = min(bytes, info->bytes);
+
+ info->bytes -= to_free;
+ info->offset += to_free;
+ if (info->bytes) {
+ ret = link_free_space(ctl, info);
+ WARN_ON(ret);
+ } else {
+ kmem_cache_free(btrfs_free_space_cachep, info);
+ }
- if (!info->bitmap && info->offset <= offset &&
- info->offset + info->bytes >= offset + bytes) {
- u64 old_start = info->offset;
- /*
- * we're freeing space in the middle of the info,
- * this can happen during tree log replay
- *
- * first unlink the old info and then
- * insert it again after the hole we're creating
- */
- unlink_free_space(ctl, info);
- if (offset + bytes < info->offset + info->bytes) {
- u64 old_end = info->offset + info->bytes;
+ offset += to_free;
+ bytes -= to_free;
+ goto again;
+ } else {
+ u64 old_end = info->bytes + info->offset;
- info->offset = offset + bytes;
- info->bytes = old_end - info->offset;
+ info->bytes = offset - info->offset;
ret = link_free_space(ctl, info);
WARN_ON(ret);
if (ret)
goto out_lock;
- } else {
- /* the hole we're creating ends at the end
- * of the info struct, just free the info
- */
- kmem_cache_free(btrfs_free_space_cachep, info);
- }
- spin_unlock(&ctl->tree_lock);
- /* step two, insert a new info struct to cover
- * anything before the hole
- */
- ret = btrfs_add_free_space(block_group, old_start,
- offset - old_start);
- WARN_ON(ret); /* -ENOMEM */
- goto out;
+ /* Not enough bytes in this entry to satisfy us */
+ if (old_end < offset + bytes) {
+ bytes -= old_end - offset;
+ offset = old_end;
+ goto again;
+ } else if (old_end == offset + bytes) {
+ /* all done */
+ goto out_lock;
+ }
+ spin_unlock(&ctl->tree_lock);
+
+ ret = btrfs_add_free_space(block_group, offset + bytes,
+ old_end - (offset + bytes));
+ WARN_ON(ret);
+ goto out;
+ }
}
ret = remove_from_bitmap(ctl, info, &offset, &bytes);
btrfs_wait_ordered_range(inode, 0, (u64)-1);
if (root->fs_info->log_root_recovering) {
- BUG_ON(!test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
+ BUG_ON(test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
&BTRFS_I(inode)->runtime_flags));
goto no_delete;
}
bh_result->b_size = len;
bh_result->b_bdev = em->bdev;
set_buffer_mapped(bh_result);
- if (create && !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
- set_buffer_new(bh_result);
+ if (create) {
+ if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+ set_buffer_new(bh_result);
+
+ /*
+ * Need to update the i_size under the extent lock so buffered
+ * readers will get the updated i_size when we unlock.
+ */
+ if (start + len > i_size_read(inode))
+ i_size_write(inode, start + len);
+ }
free_extent_map(em);
*/
ordered = btrfs_lookup_ordered_range(inode, lockstart,
lockend - lockstart + 1);
- if (!ordered)
+
+ /*
+ * We need to make sure there are no buffered pages in this
+ * range either, we could have raced between the invalidate in
+ * generic_file_direct_write and locking the extent. The
+ * invalidate needs to happen so that reads after a write do not
+ * get stale data.
+ */
+ if (!ordered && (!writing ||
+ !test_range_bit(&BTRFS_I(inode)->io_tree,
+ lockstart, lockend, EXTENT_UPTODATE, 0,
+ cached_state)))
break;
+
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
&cached_state, GFP_NOFS);
- btrfs_start_ordered_extent(inode, ordered, 1);
- btrfs_put_ordered_extent(ordered);
+
+ if (ordered) {
+ btrfs_start_ordered_extent(inode, ordered, 1);
+ btrfs_put_ordered_extent(ordered);
+ } else {
+ /* Screw you mmap */
+ ret = filemap_write_and_wait_range(file->f_mapping,
+ lockstart,
+ lockend);
+ if (ret)
+ goto out;
+
+ /*
+ * If we found a page that couldn't be invalidated just
+ * fall back to buffered.
+ */
+ ret = invalidate_inode_pages2_range(file->f_mapping,
+ lockstart >> PAGE_CACHE_SHIFT,
+ lockend >> PAGE_CACHE_SHIFT);
+ if (ret) {
+ if (ret == -EBUSY)
+ ret = 0;
+ goto out;
+ }
+ }
+
cond_resched();
}
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
struct btrfs_ioctl_vol_args_v2)
-#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \
struct btrfs_ioctl_scrub_args)
if (ret)
goto restore;
+ ret = btrfs_resume_balance_async(fs_info);
+ if (ret)
+ goto restore;
+
sb->s_flags &= ~MS_RDONLY;
}
kfree(name);
iput(inode);
+
+ btrfs_run_delayed_items(trans, root);
return ret;
}
ret = btrfs_unlink_inode(trans, root, dir,
inode, victim_name,
victim_name_len);
+ btrfs_run_delayed_items(trans, root);
}
kfree(victim_name);
ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
ret = btrfs_unlink_inode(trans, root, dir, inode,
name, name_len);
BUG_ON(ret);
+
+ btrfs_run_delayed_items(trans, root);
+
kfree(name);
iput(inode);
static int balance_kthread(void *data)
{
- struct btrfs_balance_control *bctl =
- (struct btrfs_balance_control *)data;
- struct btrfs_fs_info *fs_info = bctl->fs_info;
+ struct btrfs_fs_info *fs_info = data;
int ret = 0;
mutex_lock(&fs_info->volume_mutex);
mutex_lock(&fs_info->balance_mutex);
- set_balance_control(bctl);
-
- if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
- printk(KERN_INFO "btrfs: force skipping balance\n");
- } else {
+ if (fs_info->balance_ctl) {
printk(KERN_INFO "btrfs: continuing balance\n");
- ret = btrfs_balance(bctl, NULL);
+ ret = btrfs_balance(fs_info->balance_ctl, NULL);
}
mutex_unlock(&fs_info->balance_mutex);
mutex_unlock(&fs_info->volume_mutex);
+
return ret;
}
-int btrfs_recover_balance(struct btrfs_root *tree_root)
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
{
struct task_struct *tsk;
+
+ spin_lock(&fs_info->balance_lock);
+ if (!fs_info->balance_ctl) {
+ spin_unlock(&fs_info->balance_lock);
+ return 0;
+ }
+ spin_unlock(&fs_info->balance_lock);
+
+ if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
+ printk(KERN_INFO "btrfs: force skipping balance\n");
+ return 0;
+ }
+
+ tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
+ if (IS_ERR(tsk))
+ return PTR_ERR(tsk);
+
+ return 0;
+}
+
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
+{
struct btrfs_balance_control *bctl;
struct btrfs_balance_item *item;
struct btrfs_disk_balance_args disk_bargs;
if (!path)
return -ENOMEM;
- bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
- if (!bctl) {
- ret = -ENOMEM;
- goto out;
- }
-
key.objectid = BTRFS_BALANCE_OBJECTID;
key.type = BTRFS_BALANCE_ITEM_KEY;
key.offset = 0;
- ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
+ ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
if (ret < 0)
- goto out_bctl;
+ goto out;
if (ret > 0) { /* ret = -ENOENT; */
ret = 0;
- goto out_bctl;
+ goto out;
+ }
+
+ bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+ if (!bctl) {
+ ret = -ENOMEM;
+ goto out;
}
leaf = path->nodes[0];
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
- bctl->fs_info = tree_root->fs_info;
- bctl->flags = btrfs_balance_flags(leaf, item) | BTRFS_BALANCE_RESUME;
+ bctl->fs_info = fs_info;
+ bctl->flags = btrfs_balance_flags(leaf, item);
+ bctl->flags |= BTRFS_BALANCE_RESUME;
btrfs_balance_data(leaf, item, &disk_bargs);
btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs);
btrfs_balance_sys(leaf, item, &disk_bargs);
btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
- tsk = kthread_run(balance_kthread, bctl, "btrfs-balance");
- if (IS_ERR(tsk))
- ret = PTR_ERR(tsk);
- else
- goto out;
+ mutex_lock(&fs_info->volume_mutex);
+ mutex_lock(&fs_info->balance_mutex);
-out_bctl:
- kfree(bctl);
+ set_balance_control(bctl);
+
+ mutex_unlock(&fs_info->balance_mutex);
+ mutex_unlock(&fs_info->volume_mutex);
out:
btrfs_free_path(path);
return ret;
BUG_ON(stripe_index >= bbio->num_stripes);
dev = bbio->stripes[stripe_index].dev;
- if (bio->bi_rw & WRITE)
- btrfs_dev_stat_inc(dev,
- BTRFS_DEV_STAT_WRITE_ERRS);
- else
- btrfs_dev_stat_inc(dev,
- BTRFS_DEV_STAT_READ_ERRS);
- if ((bio->bi_rw & WRITE_FLUSH) == WRITE_FLUSH)
- btrfs_dev_stat_inc(dev,
- BTRFS_DEV_STAT_FLUSH_ERRS);
- btrfs_dev_stat_print_on_error(dev);
+ if (dev->bdev) {
+ if (bio->bi_rw & WRITE)
+ btrfs_dev_stat_inc(dev,
+ BTRFS_DEV_STAT_WRITE_ERRS);
+ else
+ btrfs_dev_stat_inc(dev,
+ BTRFS_DEV_STAT_READ_ERRS);
+ if ((bio->bi_rw & WRITE_FLUSH) == WRITE_FLUSH)
+ btrfs_dev_stat_inc(dev,
+ BTRFS_DEV_STAT_FLUSH_ERRS);
+ btrfs_dev_stat_print_on_error(dev);
+ }
}
}
int btrfs_init_new_device(struct btrfs_root *root, char *path);
int btrfs_balance(struct btrfs_balance_control *bctl,
struct btrfs_ioctl_balance_args *bargs);
-int btrfs_recover_balance(struct btrfs_root *tree_root);
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
static struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block, int size)
{
+ int ret;
+ struct buffer_head *bh;
+
/* Size must be multiple of hard sectorsize */
if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
(size < 512 || size > PAGE_SIZE))) {
return NULL;
}
- for (;;) {
- struct buffer_head * bh;
- int ret;
+retry:
+ bh = __find_get_block(bdev, block, size);
+ if (bh)
+ return bh;
+ ret = grow_buffers(bdev, block, size);
+ if (ret == 0) {
+ free_more_memory();
+ goto retry;
+ } else if (ret > 0) {
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;
-
- ret = grow_buffers(bdev, block, size);
- if (ret < 0)
- return NULL;
- if (ret == 0)
- free_more_memory();
}
+ return NULL;
}
/*
* If yes, we have encountered a double deliminator
* reset the NULL character to the deliminator
*/
- if (tmp_end < end && tmp_end[1] == delim)
+ if (tmp_end < end && tmp_end[1] == delim) {
tmp_end[0] = delim;
- /* Keep iterating until we get to a single deliminator
- * OR the end
- */
- while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
- (tmp_end[1] == delim)) {
- tmp_end = (char *) &tmp_end[2];
- }
+ /* Keep iterating until we get to a single
+ * deliminator OR the end
+ */
+ while ((tmp_end = strchr(tmp_end, delim))
+ != NULL && (tmp_end[1] == delim)) {
+ tmp_end = (char *) &tmp_end[2];
+ }
- /* Reset var options to point to next element */
- if (tmp_end) {
- tmp_end[0] = '\0';
- options = (char *) &tmp_end[1];
- } else
- /* Reached the end of the mount option string */
- options = end;
+ /* Reset var options to point to next element */
+ if (tmp_end) {
+ tmp_end[0] = '\0';
+ options = (char *) &tmp_end[1];
+ } else
+ /* Reached the end of the mount option
+ * string */
+ options = end;
+ }
/* Now build new password string */
temp_len = strlen(value);
* MS-CIFS indicates that servers are only limited by the client's
* bufsize for reads, testing against win98se shows that it throws
* INVALID_PARAMETER errors if you try to request too large a read.
+ * OS/2 just sends back short reads.
*
- * If the server advertises a MaxBufferSize of less than one page,
- * assume that it also can't satisfy reads larger than that either.
- *
- * FIXME: Is there a better heuristic for this?
+ * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+ * it can't handle a read request larger than its MaxBufferSize either.
*/
if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
defsize = CIFS_DEFAULT_IOSIZE;
else if (server->capabilities & CAP_LARGE_READ_X)
defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
- else if (server->maxBuf >= PAGE_CACHE_SIZE)
- defsize = CIFSMaxBufSize;
else
defsize = server->maxBuf - sizeof(READ_RSP);
(*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
if (!IS_ERR(*lower_file))
goto out;
- if (flags & O_RDONLY) {
+ if ((flags & O_ACCMODE) == O_RDONLY) {
rc = PTR_ERR((*lower_file));
goto out;
}
mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
- BUG_ON(rc || !daemon);
+ if (rc || !daemon) {
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return -EINVAL;
+ }
mutex_lock(&daemon->mux);
mutex_unlock(&ecryptfs_daemon_hash_mux);
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
goto out_unlock_daemon;
}
daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
+ file->private_data = daemon;
atomic_inc(&ecryptfs_num_miscdev_opens);
out_unlock_daemon:
mutex_unlock(&daemon->mux);
mutex_lock(&ecryptfs_daemon_hash_mux);
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
- BUG_ON(rc || !daemon);
+ if (rc || !daemon)
+ daemon = file->private_data;
mutex_lock(&daemon->mux);
- BUG_ON(daemon->pid != task_pid(current));
BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
atomic_dec(&ecryptfs_num_miscdev_opens);
struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
u16 msg_flags, struct ecryptfs_daemon *daemon)
{
- int rc = 0;
+ struct ecryptfs_message *msg;
- mutex_lock(&msg_ctx->mux);
- msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
- GFP_KERNEL);
- if (!msg_ctx->msg) {
- rc = -ENOMEM;
+ msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
+ if (!msg) {
printk(KERN_ERR "%s: Out of memory whilst attempting "
"to kmalloc(%zd, GFP_KERNEL)\n", __func__,
- (sizeof(*msg_ctx->msg) + data_size));
- goto out_unlock;
+ (sizeof(*msg) + data_size));
+ return -ENOMEM;
}
+
+ mutex_lock(&msg_ctx->mux);
+ msg_ctx->msg = msg;
msg_ctx->msg->index = msg_ctx->index;
msg_ctx->msg->data_len = data_size;
msg_ctx->type = msg_type;
memcpy(msg_ctx->msg->data, data, data_size);
msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
- mutex_lock(&daemon->mux);
list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
+ mutex_unlock(&msg_ctx->mux);
+
+ mutex_lock(&daemon->mux);
daemon->num_queued_msg_ctx++;
wake_up_interruptible(&daemon->wait);
mutex_unlock(&daemon->mux);
-out_unlock:
- mutex_unlock(&msg_ctx->mux);
- return rc;
+
+ return 0;
}
/*
mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
- BUG_ON(rc || !daemon);
+ if (rc || !daemon) {
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return -EINVAL;
+ }
mutex_lock(&daemon->mux);
+ if (task_pid(current) != daemon->pid) {
+ mutex_unlock(&daemon->mux);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return -EPERM;
+ }
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
rc = 0;
mutex_unlock(&ecryptfs_daemon_hash_mux);
* message from the queue; try again */
goto check_list;
}
- BUG_ON(euid != daemon->euid);
- BUG_ON(current_user_ns() != daemon->user_ns);
- BUG_ON(task_pid(current) != daemon->pid);
msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
struct ecryptfs_msg_ctx, daemon_out_list);
BUG_ON(!msg_ctx);
fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent)
{
int len = *lenp;
- u32 ipos_h, ipos_m, ipos_l;
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ loff_t i_pos;
if (len < 5) {
*lenp = 5;
return 255; /* no room */
}
- ipos_h = MSDOS_I(inode)->i_pos >> 8;
- ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
- ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28;
+ i_pos = fat_i_pos_read(sbi, inode);
*lenp = 5;
fh[0] = inode->i_ino;
fh[1] = inode->i_generation;
- fh[2] = ipos_h;
- fh[3] = ipos_m | MSDOS_I(inode)->i_logstart;
- fh[4] = ipos_l;
+ fh[2] = i_pos >> 8;
+ fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart;
+ fh[4] = (i_pos & 0x0f) << 28;
if (parent)
fh[4] |= MSDOS_I(parent)->i_logstart;
return 3;
case F_WRLCK:
return generic_add_lease(filp, arg, flp);
default:
- BUG();
+ return -EINVAL;
}
}
EXPORT_SYMBOL(generic_setlease);
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
if (!nfs_pageio_add_request(&desc, req)) {
+ nfs_list_remove_request(req);
nfs_list_add_request(req, &failed);
spin_lock(cinfo.lock);
dreq->flags = 0;
}
nfs_pageio_complete(&desc);
- while (!list_empty(&failed))
+ while (!list_empty(&failed)) {
+ req = nfs_list_entry(failed.next);
+ nfs_list_remove_request(req);
nfs_unlock_and_release_request(req);
+ }
if (put_dreq(dreq))
nfs_direct_write_complete(dreq, dreq->inode);
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+ mount_info->fill_super = nfs4_fill_super;
+
export_path = data->nfs_server.export_path;
data->nfs_server.export_path = "/";
root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
stats->ls_gets++;
stats->ls_total += ktime_to_ns(kt);
/* overflow */
- if (unlikely(stats->ls_gets) == 0) {
+ if (unlikely(stats->ls_gets == 0)) {
stats->ls_gets++;
stats->ls_total = ktime_to_ns(kt);
}
static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
struct ocfs2_lock_res *lockres)
{
+ unsigned long flags;
+
assert_spin_locked(&lockres->l_lock);
if (lockres->l_flags & OCFS2_LOCK_FREEING) {
lockres_or_flags(lockres, OCFS2_LOCK_QUEUED);
- spin_lock(&osb->dc_task_lock);
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
if (list_empty(&lockres->l_blocked_list)) {
list_add_tail(&lockres->l_blocked_list,
&osb->blocked_lock_list);
osb->blocked_lock_count++;
}
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
}
static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
{
unsigned long processed;
+ unsigned long flags;
struct ocfs2_lock_res *lockres;
- spin_lock(&osb->dc_task_lock);
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
/* grab this early so we know to try again if a state change and
* wake happens part-way through our work */
osb->dc_work_sequence = osb->dc_wake_sequence;
struct ocfs2_lock_res, l_blocked_list);
list_del_init(&lockres->l_blocked_list);
osb->blocked_lock_count--;
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
BUG_ON(!processed);
processed--;
ocfs2_process_blocked_lock(osb, lockres);
- spin_lock(&osb->dc_task_lock);
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
}
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
}
static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb)
{
int empty = 0;
+ unsigned long flags;
- spin_lock(&osb->dc_task_lock);
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
if (list_empty(&osb->blocked_lock_list))
empty = 1;
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
return empty;
}
static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
{
int should_wake = 0;
+ unsigned long flags;
- spin_lock(&osb->dc_task_lock);
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
if (osb->dc_work_sequence != osb->dc_wake_sequence)
should_wake = 1;
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
return should_wake;
}
void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
{
- spin_lock(&osb->dc_task_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&osb->dc_task_lock, flags);
/* make sure the voting thread gets a swipe at whatever changes
* the caller may have made to the voting state */
osb->dc_wake_sequence++;
- spin_unlock(&osb->dc_task_lock);
+ spin_unlock_irqrestore(&osb->dc_task_lock, flags);
wake_up(&osb->dc_event);
}
ocfs2_inode_unlock(inode, 0);
out:
- if (ret && ret != -ENXIO)
- ret = -ENXIO;
return ret;
}
if (ret < 0)
mlog_errno(ret);
- if (file->f_flags & O_SYNC)
+ if (file && (file->f_flags & O_SYNC))
handle->h_sync = 1;
ocfs2_commit_trans(osb, handle);
unaligned_dio = 0;
}
- if (unaligned_dio)
+ if (unaligned_dio) {
+ ocfs2_iocb_clear_unaligned_aio(iocb);
atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio);
+ }
out:
if (rw_level != -1)
msecs_to_jiffies(oinfo->dqi_syncms));
out_err:
- if (status)
- mlog_errno(status);
return status;
out_unlock:
ocfs2_unlock_global_qf(oinfo, 0);
{
struct file *file;
struct inode *inode;
- int error;
+ int error, fput_needed;
error = -EBADF;
- file = fget(fd);
+ file = fget_raw_light(fd, &fput_needed);
if (!file)
goto out;
if (!error)
set_fs_pwd(current->fs, &file->f_path);
out_putf:
- fput(file);
+ fput_light(file, fput_needed);
out:
return error;
}
/* prevent the page from being discarded on memory pressure */
SetPageDirty(page);
+ SetPageUptodate(page);
unlock_page(page);
put_page(page);
* Check if we need to grow the arrays holding pages and partial page
* descriptions.
*/
-int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
+int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
{
- if (pipe->buffers <= PIPE_DEF_BUFFERS)
+ unsigned int buffers = ACCESS_ONCE(pipe->buffers);
+
+ spd->nr_pages_max = buffers;
+ if (buffers <= PIPE_DEF_BUFFERS)
return 0;
- spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);
- spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL);
+ spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL);
+ spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL);
if (spd->pages && spd->partial)
return 0;
return -ENOMEM;
}
-void splice_shrink_spd(struct pipe_inode_info *pipe,
- struct splice_pipe_desc *spd)
+void splice_shrink_spd(struct splice_pipe_desc *spd)
{
- if (pipe->buffers <= PIPE_DEF_BUFFERS)
+ if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
return;
kfree(spd->pages);
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &page_cache_pipe_buf_ops,
.spd_release = spd_release_page,
index = *ppos >> PAGE_CACHE_SHIFT;
loff = *ppos & ~PAGE_CACHE_MASK;
req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- nr_pages = min(req_pages, pipe->buffers);
+ nr_pages = min(req_pages, spd.nr_pages_max);
/*
* Lookup the (hopefully) full range of pages we need.
if (spd.nr_pages)
error = splice_to_pipe(pipe, &spd);
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
return error;
}
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &default_pipe_buf_ops,
.spd_release = spd_release_page,
res = -ENOMEM;
vec = __vec;
- if (pipe->buffers > PIPE_DEF_BUFFERS) {
- vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL);
+ if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
+ vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
if (!vec)
goto shrink_ret;
}
offset = *ppos & ~PAGE_CACHE_MASK;
nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) {
+ for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
struct page *page;
page = alloc_page(GFP_USER);
shrink_ret:
if (vec != __vec)
kfree(vec);
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
return res;
err:
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &user_page_pipe_buf_ops,
.spd_release = spd_release_page,
spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
spd.partial, false,
- pipe->buffers);
+ spd.nr_pages_max);
if (spd.nr_pages <= 0)
ret = spd.nr_pages;
else
ret = splice_to_pipe(pipe, &spd);
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
return ret;
}
(x)->ki_dtor = NULL; \
(x)->ki_obj.tsk = tsk; \
(x)->ki_user_data = 0; \
+ (x)->private = NULL; \
} while (0)
#define AIO_RING_MAGIC 0xa10a10a1
extern void blk_complete_request(struct request *);
extern void __blk_complete_request(struct request *);
extern void blk_abort_request(struct request *);
-extern void blk_abort_queue(struct request_queue *);
extern void blk_unprep_request(struct request *);
/*
unsigned long size,
unsigned long align,
unsigned long goal);
+void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+ unsigned long size,
+ unsigned long align,
+ unsigned long goal,
+ unsigned long limit);
extern void *__alloc_bootmem_low(unsigned long size,
unsigned long align,
unsigned long goal);
/* Gpio pin is open source */
#define GPIOF_OPEN_SOURCE (1 << 3)
-#define GPIOF_EXPORT (1 << 2)
-#define GPIOF_EXPORT_CHANGEABLE (1 << 3)
+#define GPIOF_EXPORT (1 << 4)
+#define GPIOF_EXPORT_CHANGEABLE (1 << 5)
#define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
#define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
* @lock: lock protecting the base and associated clock bases
* and timers
* @active_bases: Bitfield to mark bases with active timers
+ * @clock_was_set: Indicates that clock was set from irq context.
* @expires_next: absolute time of the next event which was scheduled
* via clock_set_next_event()
* @hres_active: State of high resolution mode
*/
struct hrtimer_cpu_base {
raw_spinlock_t lock;
- unsigned long active_bases;
+ unsigned int active_bases;
+ unsigned int clock_was_set;
#ifdef CONFIG_HIGH_RES_TIMERS
ktime_t expires_next;
int hres_active;
# define MONOTONIC_RES_NSEC HIGH_RES_NSEC
# define KTIME_MONOTONIC_RES KTIME_HIGH_RES
+extern void clock_was_set_delayed(void);
+
#else
# define MONOTONIC_RES_NSEC LOW_RES_NSEC
{
return 0;
}
+
+static inline void clock_was_set_delayed(void) { }
+
#endif
extern void clock_was_set(void);
extern ktime_t ktime_get_real(void);
extern ktime_t ktime_get_boottime(void);
extern ktime_t ktime_get_monotonic_offset(void);
+extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot);
DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
/**
* EVIOCGMTSLOTS(len) - get MT slot values
+ * @len: size of the data buffer in bytes
*
* The ioctl buffer argument should be binary equivalent to
*
#ifdef CONFIG_HAVE_KVM_EVENTFD
void kvm_eventfd_init(struct kvm *kvm);
-int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
+int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
void kvm_irqfd_release(struct kvm *kvm);
void kvm_irq_routing_update(struct kvm *, struct kvm_irq_routing_table *);
int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
static inline void kvm_eventfd_init(struct kvm *kvm) {}
-static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
{
return -EINVAL;
}
phys_addr_t size, phys_addr_t align, int nid);
phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align);
-int memblock_free_reserved_regions(void);
-int memblock_reserve_reserved_regions(void);
-
+phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
void memblock_allow_resize(void);
int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
int memblock_add(phys_addr_t base, phys_addr_t size);
bool buck_voltage_lock;
int buck_gpios[3];
+ int buck_ds[3];
int buck2_voltage[8];
bool buck2_gpiodvs;
int buck3_voltage[8];
bool buck2_ramp_enable;
bool buck3_ramp_enable;
bool buck4_ramp_enable;
+
+ int buck2_init;
+ int buck3_init;
+ int buck4_init;
};
#endif /* __LINUX_MFD_S5M_CORE_H */
* Board data may be used to initialize regulator.
*/
struct tps65217_board {
- struct regulator_init_data *tps65217_init_data;
+ struct regulator_init_data *tps65217_init_data[TPS65217_NUM_REGULATOR];
+ struct device_node *of_node[TPS65217_NUM_REGULATOR];
};
/**
* @max_uV: minimum micro volts
* @vsel_to_uv: Function pointer to get voltage from selector
* @uv_to_vsel: Function pointer to get selector from voltage
- * @table: Table for non-uniform voltage step-size
- * @table_len: Length of the voltage table
- * @enable_mask: Regulator enable mask bits
- * @set_vout_reg: Regulator output voltage set register
- * @set_vout_mask: Regulator output voltage set mask
*
* This data is used to check the regualtor voltage limits while setting.
*/
int max_uV;
int (*vsel_to_uv)(unsigned int vsel);
int (*uv_to_vsel)(int uV, unsigned int *vsel);
- const int *table;
- unsigned int table_len;
- unsigned int enable_mask;
- unsigned int set_vout_reg;
- unsigned int set_vout_mask;
};
/**
return regmap_update_bits(tps65910->regmap, reg, mask, 0);
}
+static inline int tps65910_reg_update_bits(struct tps65910 *tps65910, u8 reg,
+ u8 mask, u8 val)
+{
+ return regmap_update_bits(tps65910->regmap, reg, mask, val);
+}
+
#endif /* __LINUX_MFD_TPS65910_H */
range, including holes */
int node_id;
wait_queue_head_t kswapd_wait;
- struct task_struct *kswapd;
+ struct task_struct *kswapd; /* Protected by lock_memory_hotplug() */
int kswapd_max_order;
enum zone_type classzone_idx;
} pg_data_t;
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
/* Provide indication device is assigned by a Virtual Machine Manager */
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
- /* Device causes system crash if in D3 during S3 sleep */
- PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8,
};
enum pci_irq_reroute_variant {
* Changing LSM security domain is considered a new privilege. So, for example,
* asking selinux for a specific new context (e.g. with runcon) will result
* in execve returning -EPERM.
+ *
+ * See Documentation/prctl/no_new_privs.txt for more details.
*/
#define PR_SET_NO_NEW_PRIVS 38
#define PR_GET_NO_NEW_PRIVS 39
/* Internal to kernel */
extern void rcu_sched_qs(int cpu);
extern void rcu_bh_qs(int cpu);
-extern void rcu_preempt_note_context_switch(void);
extern void rcu_check_callbacks(int cpu, int user);
struct notifier_block;
extern void rcu_idle_enter(void);
#ifdef CONFIG_TINY_RCU
+static inline void rcu_preempt_note_context_switch(void)
+{
+}
+
static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
#else /* #ifdef CONFIG_TINY_RCU */
+void rcu_preempt_note_context_switch(void);
int rcu_preempt_needs_cpu(void);
static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
static inline void rcu_note_context_switch(int cpu)
{
rcu_sched_qs(cpu);
+ rcu_preempt_note_context_switch();
}
/*
*
* @enable_time: Time taken for the regulator voltage output voltage to
* stabilise after being enabled, in microseconds.
+ * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
+ * select ramp delay equal to or less than(closest) ramp_delay.
* @set_voltage_time_sel: Time taken for the regulator voltage output voltage
* to stabilise after being set to a new value, in microseconds.
* The function provides the from and to voltage selector, the
/* Time taken to enable or set voltage on the regulator */
int (*enable_time) (struct regulator_dev *);
+ int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
int (*set_voltage_time_sel) (struct regulator_dev *,
unsigned int old_selector,
unsigned int new_selector);
*
* @min_uV: Voltage given by the lowest selector (if linear mapping)
* @uV_step: Voltage increase with each selector (if linear mapping)
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
* @volt_table: Voltage mapping table (if table based mapping)
*
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
* @vsel_mask: Mask for register bitfield used for selector
* @enable_reg: Register for control when using regmap enable/disable ops
* @enable_mask: Mask for control when using regmap enable/disable ops
+ *
+ * @enable_time: Time taken for initial enable of regulator (in uS).
*/
struct regulator_desc {
const char *name;
unsigned int min_uV;
unsigned int uV_step;
+ unsigned int ramp_delay;
const unsigned int *volt_table;
unsigned int vsel_mask;
unsigned int enable_reg;
unsigned int enable_mask;
+
+ unsigned int enable_time;
};
/**
* @of_node: OpenFirmware node to parse for device tree bindings (may be
* NULL).
* @regmap: regmap to use for core regmap helpers
+ * @ena_gpio: GPIO controlling regulator enable.
+ * @ena_gpio_invert: Sense for GPIO enable control.
+ * @ena_gpio_flags: Flags to use when calling gpio_request_one()
*/
struct regulator_config {
struct device *dev;
void *driver_data;
struct device_node *of_node;
struct regmap *regmap;
+
+ int ena_gpio;
+ unsigned int ena_gpio_invert:1;
+ unsigned int ena_gpio_flags;
};
/*
void *reg_data; /* regulator_dev data */
struct dentry *debugfs;
+
+ int ena_gpio;
+ unsigned int ena_gpio_invert:1;
+ unsigned int ena_gpio_state:1;
};
struct regulator_dev *
int regulator_is_enabled_regmap(struct regulator_dev *rdev);
int regulator_enable_regmap(struct regulator_dev *rdev);
int regulator_disable_regmap(struct regulator_dev *rdev);
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector);
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
/**
* struct fixed_voltage_config - fixed_voltage_config structure
* @supply_name: Name of the regulator supply
+ * @input_supply: Name of the input regulator supply
* @microvolts: Output voltage of regulator
* @gpio: GPIO to use for enable control
* set to -EINVAL if not used
*/
struct fixed_voltage_config {
const char *supply_name;
+ const char *input_supply;
int microvolts;
int gpio;
unsigned startup_delay;
--- /dev/null
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * 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 __LP872X_REGULATOR_H__
+#define __LP872X_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define LP872X_MAX_REGULATORS 9
+
+enum lp872x_regulator_id {
+ LP8720_ID_BASE,
+ LP8720_ID_LDO1 = LP8720_ID_BASE,
+ LP8720_ID_LDO2,
+ LP8720_ID_LDO3,
+ LP8720_ID_LDO4,
+ LP8720_ID_LDO5,
+ LP8720_ID_BUCK,
+
+ LP8725_ID_BASE,
+ LP8725_ID_LDO1 = LP8725_ID_BASE,
+ LP8725_ID_LDO2,
+ LP8725_ID_LDO3,
+ LP8725_ID_LDO4,
+ LP8725_ID_LDO5,
+ LP8725_ID_LILO1,
+ LP8725_ID_LILO2,
+ LP8725_ID_BUCK1,
+ LP8725_ID_BUCK2,
+
+ LP872X_ID_MAX,
+};
+
+enum lp872x_dvs_state {
+ DVS_LOW = GPIOF_OUT_INIT_LOW,
+ DVS_HIGH = GPIOF_OUT_INIT_HIGH,
+};
+
+enum lp872x_dvs_sel {
+ SEL_V1,
+ SEL_V2,
+};
+
+/**
+ * lp872x_dvs
+ * @gpio : gpio pin number for dvs control
+ * @vsel : dvs selector for buck v1 or buck v2 register
+ * @init_state : initial dvs pin state
+ */
+struct lp872x_dvs {
+ int gpio;
+ enum lp872x_dvs_sel vsel;
+ enum lp872x_dvs_state init_state;
+};
+
+/**
+ * lp872x_regdata
+ * @id : regulator id
+ * @init_data : init data for each regulator
+ */
+struct lp872x_regulator_data {
+ enum lp872x_regulator_id id;
+ struct regulator_init_data *init_data;
+};
+
+/**
+ * lp872x_platform_data
+ * @general_config : the value of LP872X_GENERAL_CFG register
+ * @update_config : if LP872X_GENERAL_CFG register is updated, set true
+ * @regulator_data : platform regulator id and init data
+ * @dvs : dvs data for buck voltage control
+ */
+struct lp872x_platform_data {
+ u8 general_config;
+ bool update_config;
+ struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS];
+ struct lp872x_dvs *dvs;
+};
+
+#endif
* mode.
* @initial_state: Suspend state to set by default.
* @initial_mode: Mode to set at startup.
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
*/
struct regulation_constraints {
/* mode to set on startup */
unsigned int initial_mode;
+ unsigned int ramp_delay;
+
/* constraint flags */
unsigned always_on:1; /* regulator never off when system is on */
unsigned boot_on:1; /* bootloader/firmware enabled regulator */
#include <linux/types.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
/* The feature bitmap for virtio rpmsg */
#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
/**
* struct rpmsg_endpoint - binds a local rpmsg address to its user
* @rpdev: rpmsg channel device
+ * @refcount: when this drops to zero, the ept is deallocated
* @cb: rx callback handler
+ * @cb_lock: must be taken before accessing/changing @cb
* @addr: local rpmsg address
* @priv: private data for the driver's use
*
*/
struct rpmsg_endpoint {
struct rpmsg_channel *rpdev;
+ struct kref refcount;
rpmsg_rx_cb_t cb;
+ struct mutex cb_lock;
u32 addr;
void *priv;
};
INIT_LIST_HEAD(&p->rcu_node_entry);
}
-static inline void rcu_switch_from(struct task_struct *prev)
-{
- if (prev->rcu_read_lock_nesting != 0)
- rcu_preempt_note_context_switch();
-}
-
#else
static inline void rcu_copy_process(struct task_struct *p)
{
}
-static inline void rcu_switch_from(struct task_struct *prev)
-{
-}
-
#endif
#ifdef CONFIG_SMP
}
#endif
+#ifdef CONFIG_NO_HZ
+void calc_load_enter_idle(void);
+void calc_load_exit_idle(void);
+#else
+static inline void calc_load_enter_idle(void) { }
+static inline void calc_load_exit_idle(void) { }
+#endif /* CONFIG_NO_HZ */
+
#ifndef CONFIG_CPUMASK_OFFSTACK
static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
{
struct splice_pipe_desc {
struct page **pages; /* page map */
struct partial_page *partial; /* pages[] may not be contig */
- int nr_pages; /* number of pages in map */
+ int nr_pages; /* number of populated pages in map */
+ unsigned int nr_pages_max; /* pages[] & partial[] arrays size */
unsigned int flags; /* splice flags */
const struct pipe_buf_operations *ops;/* ops associated with output pipe */
void (*spd_release)(struct splice_pipe_desc *, unsigned int);
/*
* for dynamic pipe sizing
*/
-extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *);
-extern void splice_shrink_spd(struct pipe_inode_info *,
- struct splice_pipe_desc *);
+extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *);
+extern void splice_shrink_spd(struct splice_pipe_desc *);
extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
/* Is this structure kfree()able? */
malloced:1;
+ /* Has this transport moved the ctsn since we last sacked */
+ __u32 sack_generation;
+
struct flowi fl;
/* This is the peer's IP address and port. */
*/
__u8 sack_needed; /* Do we need to sack the peer? */
__u32 sack_cnt;
+ __u32 sack_generation;
/* These are capabilities which our peer advertised. */
__u8 ecn_capable:1, /* Can peer do ECN? */
int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
/* Mark this TSN as seen. */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+ struct sctp_transport *trans);
/* Mark this TSN and all lower as seen. */
void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
ATAPI_COMMAND_SET = 1,
};
+#define ATA_RESP_FIS_SIZE 24
+
struct sata_device {
enum ata_command_set command_set;
struct smp_resp rps_resp; /* report_phy_sata_resp */
struct ata_port *ap;
struct ata_host ata_host;
- struct ata_taskfile tf;
+ u8 fis[ATA_RESP_FIS_SIZE];
};
enum {
*/
struct ata_task_resp {
u16 frame_len;
- u8 ending_fis[24]; /* dev to host or data-in */
+ u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */
};
#define SAS_STATUS_BUF_SIZE 96
static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
{
+ struct scsi_driver **sdp;
+
if (!cmd->request->rq_disk)
return NULL;
- return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+ sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data;
+ if (!sdp)
+ return NULL;
+
+ return *sdp;
}
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
mutex_unlock(&cgroup_mutex);
/*
- * We want to drop the active superblock reference from the
- * cgroup creation after all the dentry refs are gone -
- * kill_sb gets mighty unhappy otherwise. Mark
- * dentry->d_fsdata with cgroup_diput() to tell
- * cgroup_d_release() to call deactivate_super().
+ * Drop the active superblock reference that we took when we
+ * created the cgroup
*/
- dentry->d_fsdata = cgroup_diput;
+ deactivate_super(cgrp->root->sb);
/*
* if we're getting rid of the cgroup, refcount should ensure
return 1;
}
-static void cgroup_d_release(struct dentry *dentry)
-{
- /* did cgroup_diput() tell me to deactivate super? */
- if (dentry->d_fsdata == cgroup_diput)
- deactivate_super(dentry->d_sb);
-}
-
static void remove_dir(struct dentry *d)
{
struct dentry *parent = dget(d->d_parent);
static const struct dentry_operations cgroup_dops = {
.d_iput = cgroup_diput,
.d_delete = cgroup_delete,
- .d_release = cgroup_d_release,
};
struct inode *inode =
{
struct cgroup_subsys_state *css =
container_of(work, struct cgroup_subsys_state, dput_work);
+ struct dentry *dentry = css->cgroup->dentry;
+ struct super_block *sb = dentry->d_sb;
- dput(css->cgroup->dentry);
+ atomic_inc(&sb->s_active);
+ dput(dentry);
+ deactivate_super(sb);
}
static void init_cgroup_css(struct cgroup_subsys_state *css,
}
err = arch_dup_task_struct(tsk, orig);
- if (err)
- goto out;
+ /*
+ * We defer looking at err, because we will need this setup
+ * for the clean up path to work correctly.
+ */
tsk->stack = ti;
-
setup_thread_stack(tsk, orig);
+
+ if (err)
+ goto out;
+
clear_user_return_notifier(tsk);
clear_tsk_need_resched(tsk);
stackend = end_of_stack(tsk);
return 0;
}
+static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
+{
+ ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
+ ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
+
+ return ktime_get_update_offsets(offs_real, offs_boot);
+}
+
/*
* Retrigger next event is called after clock was set
*
static void retrigger_next_event(void *arg)
{
struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
- struct timespec realtime_offset, xtim, wtm, sleep;
if (!hrtimer_hres_active())
return;
- /* Optimized out for !HIGH_RES */
- get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep);
- set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
-
- /* Adjust CLOCK_REALTIME offset */
raw_spin_lock(&base->lock);
- base->clock_base[HRTIMER_BASE_REALTIME].offset =
- timespec_to_ktime(realtime_offset);
- base->clock_base[HRTIMER_BASE_BOOTTIME].offset =
- timespec_to_ktime(sleep);
-
+ hrtimer_update_base(base);
hrtimer_force_reprogram(base, 0);
raw_spin_unlock(&base->lock);
}
base->clock_base[i].resolution = KTIME_HIGH_RES;
tick_setup_sched_timer();
-
/* "Retrigger" the interrupt to get things going */
retrigger_next_event(NULL);
local_irq_restore(flags);
return 1;
}
+/*
+ * Called from timekeeping code to reprogramm the hrtimer interrupt
+ * device. If called from the timer interrupt context we defer it to
+ * softirq context.
+ */
+void clock_was_set_delayed(void)
+{
+ struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
+
+ cpu_base->clock_was_set = 1;
+ __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+}
+
#else
static inline int hrtimer_hres_active(void) { return 0; }
cpu_base->nr_events++;
dev->next_event.tv64 = KTIME_MAX;
- entry_time = now = ktime_get();
+ raw_spin_lock(&cpu_base->lock);
+ entry_time = now = hrtimer_update_base(cpu_base);
retry:
expires_next.tv64 = KTIME_MAX;
-
- raw_spin_lock(&cpu_base->lock);
/*
* We set expires_next to KTIME_MAX here with cpu_base->lock
* held to prevent that a timer is enqueued in our queue via
* We need to prevent that we loop forever in the hrtimer
* interrupt routine. We give it 3 attempts to avoid
* overreacting on some spurious event.
+ *
+ * Acquire base lock for updating the offsets and retrieving
+ * the current time.
*/
- now = ktime_get();
+ raw_spin_lock(&cpu_base->lock);
+ now = hrtimer_update_base(cpu_base);
cpu_base->nr_retries++;
if (++retries < 3)
goto retry;
*/
cpu_base->nr_hangs++;
cpu_base->hang_detected = 1;
+ raw_spin_unlock(&cpu_base->lock);
delta = ktime_sub(now, entry_time);
if (delta.tv64 > cpu_base->max_hang_time.tv64)
cpu_base->max_hang_time = delta;
static void run_hrtimer_softirq(struct softirq_action *h)
{
+ struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
+
+ if (cpu_base->clock_was_set) {
+ cpu_base->clock_was_set = 0;
+ clock_was_set();
+ }
+
hrtimer_peek_ahead_timers();
}
*/
enum log_flags {
- LOG_DEFAULT = 0,
- LOG_NOCONS = 1, /* already flushed, do not print to console */
+ LOG_NOCONS = 1, /* already flushed, do not print to console */
+ LOG_NEWLINE = 2, /* text ended with a newline */
+ LOG_PREFIX = 4, /* text started with a prefix */
+ LOG_CONT = 8, /* text is a fragment of a continuation line */
};
struct log {
/* the next printk record to read by syslog(READ) or /proc/kmsg */
static u64 syslog_seq;
static u32 syslog_idx;
+static enum log_flags syslog_prev;
+static size_t syslog_partial;
/* index and sequence number of the first record stored in the buffer */
static u64 log_first_seq;
ret = mutex_lock_interruptible(&user->lock);
if (ret)
return ret;
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
while (user->seq == log_next_seq) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
goto out;
}
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
ret = wait_event_interruptible(log_wait,
user->seq != log_next_seq);
if (ret)
goto out;
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
}
if (user->seq < log_first_seq) {
user->idx = log_first_idx;
user->seq = log_first_seq;
ret = -EPIPE;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
goto out;
}
for (i = 0; i < msg->text_len; i++) {
unsigned char c = log_text(msg)[i];
- if (c < ' ' || c >= 128)
+ if (c < ' ' || c >= 127 || c == '\\')
len += sprintf(user->buf + len, "\\x%02x", c);
else
user->buf[len++] = c;
continue;
}
- if (c < ' ' || c >= 128) {
+ if (c < ' ' || c >= 127 || c == '\\') {
len += sprintf(user->buf + len, "\\x%02x", c);
continue;
}
user->idx = log_next(user->idx);
user->seq++;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
if (len > count) {
ret = -EINVAL;
if (offset)
return -ESPIPE;
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
switch (whence) {
case SEEK_SET:
/* the first record */
default:
ret = -EINVAL;
}
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
return ret;
}
poll_wait(file, &log_wait, wait);
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
if (user->seq < log_next_seq) {
/* return error when data has vanished underneath us */
if (user->seq < log_first_seq)
ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
ret = POLLIN|POLLRDNORM;
}
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
return ret;
}
mutex_init(&user->lock);
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
user->idx = log_first_idx;
user->seq = log_first_seq;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
file->private_data = user;
return 0;
static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
{
size_t len = 0;
+ unsigned int prefix = (msg->facility << 3) | msg->level;
if (syslog) {
if (buf) {
- len += sprintf(buf, "<%u>", msg->level);
+ len += sprintf(buf, "<%u>", prefix);
} else {
len += 3;
- if (msg->level > 9)
- len++;
- if (msg->level > 99)
+ if (prefix > 999)
+ len += 3;
+ else if (prefix > 99)
+ len += 2;
+ else if (prefix > 9)
len++;
}
}
return len;
}
-static size_t msg_print_text(const struct log *msg, bool syslog,
- char *buf, size_t size)
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+ bool syslog, char *buf, size_t size)
{
const char *text = log_text(msg);
size_t text_size = msg->text_len;
+ bool prefix = true;
+ bool newline = true;
size_t len = 0;
+ if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))
+ prefix = false;
+
+ if (msg->flags & LOG_CONT) {
+ if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
+ prefix = false;
+
+ if (!(msg->flags & LOG_NEWLINE))
+ newline = false;
+ }
+
do {
const char *next = memchr(text, '\n', text_size);
size_t text_len;
text_len + 1>= size - len)
break;
- len += print_prefix(msg, syslog, buf + len);
+ if (prefix)
+ len += print_prefix(msg, syslog, buf + len);
memcpy(buf + len, text, text_len);
len += text_len;
- buf[len++] = '\n';
+ if (next || newline)
+ buf[len++] = '\n';
} else {
/* SYSLOG_ACTION_* buffer size only calculation */
- len += print_prefix(msg, syslog, NULL);
- len += text_len + 1;
+ if (prefix)
+ len += print_prefix(msg, syslog, NULL);
+ len += text_len;
+ if (next || newline)
+ len++;
}
+ prefix = true;
text = next;
} while (text);
while (size > 0) {
size_t n;
+ size_t skip;
raw_spin_lock_irq(&logbuf_lock);
if (syslog_seq < log_first_seq) {
/* messages are gone, move to first one */
syslog_seq = log_first_seq;
syslog_idx = log_first_idx;
+ syslog_prev = 0;
+ syslog_partial = 0;
}
if (syslog_seq == log_next_seq) {
raw_spin_unlock_irq(&logbuf_lock);
break;
}
+
+ skip = syslog_partial;
msg = log_from_idx(syslog_idx);
- n = msg_print_text(msg, true, text, LOG_LINE_MAX);
- if (n <= size) {
+ n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX);
+ if (n - syslog_partial <= size) {
+ /* message fits into buffer, move forward */
syslog_idx = log_next(syslog_idx);
syslog_seq++;
+ syslog_prev = msg->flags;
+ n -= syslog_partial;
+ syslog_partial = 0;
+ } else if (!len){
+ /* partial read(), remember position */
+ n = size;
+ syslog_partial += n;
} else
n = 0;
raw_spin_unlock_irq(&logbuf_lock);
if (!n)
break;
- len += n;
- size -= n;
- buf += n;
- n = copy_to_user(buf - n, text, n);
-
- if (n) {
- len -= n;
+ if (copy_to_user(buf, text + skip, n)) {
if (!len)
len = -EFAULT;
break;
}
+
+ len += n;
+ size -= n;
+ buf += n;
}
kfree(text);
u64 next_seq;
u64 seq;
u32 idx;
+ enum log_flags prev;
if (clear_seq < log_first_seq) {
/* messages are gone, move to first available one */
*/
seq = clear_seq;
idx = clear_idx;
+ prev = 0;
while (seq < log_next_seq) {
struct log *msg = log_from_idx(idx);
- len += msg_print_text(msg, true, NULL, 0);
+ len += msg_print_text(msg, prev, true, NULL, 0);
idx = log_next(idx);
seq++;
}
/* move first record forward until length fits into the buffer */
seq = clear_seq;
idx = clear_idx;
+ prev = 0;
while (len > size && seq < log_next_seq) {
struct log *msg = log_from_idx(idx);
- len -= msg_print_text(msg, true, NULL, 0);
+ len -= msg_print_text(msg, prev, true, NULL, 0);
idx = log_next(idx);
seq++;
}
next_seq = log_next_seq;
len = 0;
+ prev = 0;
while (len >= 0 && seq < next_seq) {
struct log *msg = log_from_idx(idx);
int textlen;
- textlen = msg_print_text(msg, true, text, LOG_LINE_MAX);
+ textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX);
if (textlen < 0) {
len = textlen;
break;
}
idx = log_next(idx);
seq++;
+ prev = msg->flags;
raw_spin_unlock_irq(&logbuf_lock);
if (copy_to_user(buf + len, text, textlen))
/* messages are gone, move to next one */
seq = log_first_seq;
idx = log_first_idx;
+ prev = 0;
}
}
}
{
bool clear = false;
static int saved_console_loglevel = -1;
- static DEFINE_MUTEX(syslog_mutex);
int error;
error = check_syslog_permissions(type, from_file);
error = -EFAULT;
goto out;
}
- error = mutex_lock_interruptible(&syslog_mutex);
- if (error)
- goto out;
error = wait_event_interruptible(log_wait,
syslog_seq != log_next_seq);
- if (error) {
- mutex_unlock(&syslog_mutex);
+ if (error)
goto out;
- }
error = syslog_print(buf, len);
- mutex_unlock(&syslog_mutex);
break;
/* Read/clear last kernel messages */
case SYSLOG_ACTION_READ_CLEAR:
/* messages are gone, move to first one */
syslog_seq = log_first_seq;
syslog_idx = log_first_idx;
+ syslog_prev = 0;
+ syslog_partial = 0;
}
if (from_file) {
/*
*/
error = log_next_idx - syslog_idx;
} else {
- u64 seq;
- u32 idx;
+ u64 seq = syslog_seq;
+ u32 idx = syslog_idx;
+ enum log_flags prev = syslog_prev;
error = 0;
- seq = syslog_seq;
- idx = syslog_idx;
while (seq < log_next_seq) {
struct log *msg = log_from_idx(idx);
- error += msg_print_text(msg, true, NULL, 0);
+ error += msg_print_text(msg, prev, true, NULL, 0);
idx = log_next(idx);
seq++;
+ prev = msg->flags;
}
+ error -= syslog_partial;
}
raw_spin_unlock_irq(&logbuf_lock);
break;
static char textbuf[LOG_LINE_MAX];
char *text = textbuf;
size_t text_len;
+ enum log_flags lflags = 0;
unsigned long flags;
int this_cpu;
- bool newline = false;
- bool prefix = false;
int printed_len = 0;
boot_delay_msec();
recursion_bug = 0;
printed_len += strlen(recursion_msg);
/* emit KERN_CRIT message */
- log_store(0, 2, LOG_DEFAULT, 0,
+ log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
NULL, 0, recursion_msg, printed_len);
}
/* mark and strip a trailing newline */
if (text_len && text[text_len-1] == '\n') {
text_len--;
- newline = true;
+ lflags |= LOG_NEWLINE;
}
/* strip syslog prefix and extract log level or control flags */
if (level == -1)
level = text[1] - '0';
case 'd': /* KERN_DEFAULT */
- prefix = true;
+ lflags |= LOG_PREFIX;
case 'c': /* KERN_CONT */
text += 3;
text_len -= 3;
if (level == -1)
level = default_message_loglevel;
- if (dict) {
- prefix = true;
- newline = true;
- }
+ if (dict)
+ lflags |= LOG_PREFIX|LOG_NEWLINE;
- if (!newline) {
+ if (!(lflags & LOG_NEWLINE)) {
/*
* Flush the conflicting buffer. An earlier newline was missing,
* or another task also prints continuation lines.
*/
- if (cont.len && (prefix || cont.owner != current))
+ if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
cont_flush();
/* buffer line if possible, otherwise store it right away */
if (!cont_add(facility, level, text, text_len))
- log_store(facility, level, LOG_DEFAULT, 0,
+ log_store(facility, level, lflags | LOG_CONT, 0,
dict, dictlen, text, text_len);
} else {
bool stored = false;
* flush it out and store this line separately.
*/
if (cont.len && cont.owner == current) {
- if (!prefix)
+ if (!(lflags & LOG_PREFIX))
stored = cont_add(facility, level, text, text_len);
cont_flush();
}
if (!stored)
- log_store(facility, level, LOG_DEFAULT, 0,
+ log_store(facility, level, lflags, 0,
dict, dictlen, text, text_len);
}
printed_len += text_len;
static struct log *log_from_idx(u32 idx) { return NULL; }
static u32 log_next(u32 idx) { return 0; }
static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, bool syslog,
- char *buf, size_t size) { return 0; }
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+ bool syslog, char *buf, size_t size) { return 0; }
static size_t cont_print_text(char *text, size_t size) { return 0; }
#endif /* CONFIG_PRINTK */
/* the next printk record to write to the console */
static u64 console_seq;
static u32 console_idx;
+static enum log_flags console_prev;
/**
* console_unlock - unlock the console system
/* messages are gone, move to first one */
console_seq = log_first_seq;
console_idx = log_first_idx;
+ console_prev = 0;
}
skip:
if (console_seq == log_next_seq)
*/
console_idx = log_next(console_idx);
console_seq++;
+ /*
+ * We will get here again when we register a new
+ * CON_PRINTBUFFER console. Clear the flag so we
+ * will properly dump everything later.
+ */
+ msg->flags &= ~LOG_NOCONS;
goto skip;
}
level = msg->level;
- len = msg_print_text(msg, false, text, sizeof(text));
-
+ len = msg_print_text(msg, console_prev, false,
+ text, sizeof(text));
console_idx = log_next(console_idx);
console_seq++;
+ console_prev = msg->flags;
raw_spin_unlock(&logbuf_lock);
stop_critical_timings(); /* don't trace print latency */
raw_spin_lock_irqsave(&logbuf_lock, flags);
console_seq = syslog_seq;
console_idx = syslog_idx;
+ console_prev = syslog_prev;
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
/*
* We're about to replay the log buffer. Only do this to the
}
msg = log_from_idx(dumper->cur_idx);
- l = msg_print_text(msg, syslog,
- line, size);
+ l = msg_print_text(msg, 0, syslog, line, size);
dumper->cur_idx = log_next(dumper->cur_idx);
dumper->cur_seq++;
u32 idx;
u64 next_seq;
u32 next_idx;
+ enum log_flags prev;
size_t l = 0;
bool ret = false;
/* calculate length of entire buffer */
seq = dumper->cur_seq;
idx = dumper->cur_idx;
+ prev = 0;
while (seq < dumper->next_seq) {
struct log *msg = log_from_idx(idx);
- l += msg_print_text(msg, true, NULL, 0);
+ l += msg_print_text(msg, prev, true, NULL, 0);
idx = log_next(idx);
seq++;
+ prev = msg->flags;
}
/* move first record forward until length fits into the buffer */
seq = dumper->cur_seq;
idx = dumper->cur_idx;
+ prev = 0;
while (l > size && seq < dumper->next_seq) {
struct log *msg = log_from_idx(idx);
- l -= msg_print_text(msg, true, NULL, 0);
+ l -= msg_print_text(msg, prev, true, NULL, 0);
idx = log_next(idx);
seq++;
+ prev = msg->flags;
}
/* last message in next interation */
next_idx = idx;
l = 0;
+ prev = 0;
while (seq < dumper->next_seq) {
struct log *msg = log_from_idx(idx);
- l += msg_print_text(msg, syslog,
- buf + l, size - l);
-
+ l += msg_print_text(msg, prev, syslog, buf + l, size - l);
idx = log_next(idx);
seq++;
+ prev = msg->flags;
}
dumper->next_seq = next_seq;
{
trace_rcu_utilization("Start context switch");
rcu_sched_qs(cpu);
+ rcu_preempt_note_context_switch(cpu);
trace_rcu_utilization("End context switch");
}
EXPORT_SYMBOL_GPL(rcu_note_context_switch);
/* Forward declarations for rcutree_plugin.h */
static void rcu_bootup_announce(void);
long rcu_batches_completed(void);
+static void rcu_preempt_note_context_switch(int cpu);
static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
#ifdef CONFIG_HOTPLUG_CPU
static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
*
* Caller must disable preemption.
*/
-void rcu_preempt_note_context_switch(void)
+static void rcu_preempt_note_context_switch(int cpu)
{
struct task_struct *t = current;
unsigned long flags;
(t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
/* Possibly blocking in an RCU read-side critical section. */
- rdp = __this_cpu_ptr(rcu_preempt_state.rda);
+ rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
rnp = rdp->mynode;
raw_spin_lock_irqsave(&rnp->lock, flags);
t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
* means that we continue to block the current grace period.
*/
local_irq_save(flags);
- rcu_preempt_qs(smp_processor_id());
+ rcu_preempt_qs(cpu);
local_irq_restore(flags);
}
}
EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
+/*
+ * Because preemptible RCU does not exist, we never have to check for
+ * CPUs being in quiescent states.
+ */
+static void rcu_preempt_note_context_switch(int cpu)
+{
+}
+
/*
* Because preemptible RCU does not exist, there are never any preempted
* RCU readers.
struct splice_pipe_desc spd = {
.pages = pages,
.nr_pages = 0,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.partial = partial,
.flags = flags,
.ops = &relay_pipe_buf_ops,
ret += padding;
out:
- splice_shrink_spd(pipe, &spd);
- return ret;
+ splice_shrink_spd(&spd);
+ return ret;
}
static ssize_t relay_file_splice_read(struct file *in,
#endif
/* Here we just switch the register state and the stack. */
- rcu_switch_from(prev);
switch_to(prev, next, prev);
barrier();
}
+/*
+ * Global load-average calculations
+ *
+ * We take a distributed and async approach to calculating the global load-avg
+ * in order to minimize overhead.
+ *
+ * The global load average is an exponentially decaying average of nr_running +
+ * nr_uninterruptible.
+ *
+ * Once every LOAD_FREQ:
+ *
+ * nr_active = 0;
+ * for_each_possible_cpu(cpu)
+ * nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
+ *
+ * avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
+ *
+ * Due to a number of reasons the above turns in the mess below:
+ *
+ * - for_each_possible_cpu() is prohibitively expensive on machines with
+ * serious number of cpus, therefore we need to take a distributed approach
+ * to calculating nr_active.
+ *
+ * \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0
+ * = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) }
+ *
+ * So assuming nr_active := 0 when we start out -- true per definition, we
+ * can simply take per-cpu deltas and fold those into a global accumulate
+ * to obtain the same result. See calc_load_fold_active().
+ *
+ * Furthermore, in order to avoid synchronizing all per-cpu delta folding
+ * across the machine, we assume 10 ticks is sufficient time for every
+ * cpu to have completed this task.
+ *
+ * This places an upper-bound on the IRQ-off latency of the machine. Then
+ * again, being late doesn't loose the delta, just wrecks the sample.
+ *
+ * - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because
+ * this would add another cross-cpu cacheline miss and atomic operation
+ * to the wakeup path. Instead we increment on whatever cpu the task ran
+ * when it went into uninterruptible state and decrement on whatever cpu
+ * did the wakeup. This means that only the sum of nr_uninterruptible over
+ * all cpus yields the correct result.
+ *
+ * This covers the NO_HZ=n code, for extra head-aches, see the comment below.
+ */
+
/* Variables and functions for calc_load */
static atomic_long_t calc_load_tasks;
static unsigned long calc_load_update;
unsigned long avenrun[3];
-EXPORT_SYMBOL(avenrun);
+EXPORT_SYMBOL(avenrun); /* should be removed */
+
+/**
+ * get_avenrun - get the load average array
+ * @loads: pointer to dest load array
+ * @offset: offset to add
+ * @shift: shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+ loads[0] = (avenrun[0] + offset) << shift;
+ loads[1] = (avenrun[1] + offset) << shift;
+ loads[2] = (avenrun[2] + offset) << shift;
+}
static long calc_load_fold_active(struct rq *this_rq)
{
return delta;
}
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
static unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{
#ifdef CONFIG_NO_HZ
/*
- * For NO_HZ we delay the active fold to the next LOAD_FREQ update.
+ * Handle NO_HZ for the global load-average.
+ *
+ * Since the above described distributed algorithm to compute the global
+ * load-average relies on per-cpu sampling from the tick, it is affected by
+ * NO_HZ.
+ *
+ * The basic idea is to fold the nr_active delta into a global idle-delta upon
+ * entering NO_HZ state such that we can include this as an 'extra' cpu delta
+ * when we read the global state.
+ *
+ * Obviously reality has to ruin such a delightfully simple scheme:
+ *
+ * - When we go NO_HZ idle during the window, we can negate our sample
+ * contribution, causing under-accounting.
+ *
+ * We avoid this by keeping two idle-delta counters and flipping them
+ * when the window starts, thus separating old and new NO_HZ load.
+ *
+ * The only trick is the slight shift in index flip for read vs write.
+ *
+ * 0s 5s 10s 15s
+ * +10 +10 +10 +10
+ * |-|-----------|-|-----------|-|-----------|-|
+ * r:0 0 1 1 0 0 1 1 0
+ * w:0 1 1 0 0 1 1 0 0
+ *
+ * This ensures we'll fold the old idle contribution in this window while
+ * accumlating the new one.
+ *
+ * - When we wake up from NO_HZ idle during the window, we push up our
+ * contribution, since we effectively move our sample point to a known
+ * busy state.
+ *
+ * This is solved by pushing the window forward, and thus skipping the
+ * sample, for this cpu (effectively using the idle-delta for this cpu which
+ * was in effect at the time the window opened). This also solves the issue
+ * of having to deal with a cpu having been in NOHZ idle for multiple
+ * LOAD_FREQ intervals.
*
* When making the ILB scale, we should try to pull this in as well.
*/
-static atomic_long_t calc_load_tasks_idle;
+static atomic_long_t calc_load_idle[2];
+static int calc_load_idx;
-void calc_load_account_idle(struct rq *this_rq)
+static inline int calc_load_write_idx(void)
{
+ int idx = calc_load_idx;
+
+ /*
+ * See calc_global_nohz(), if we observe the new index, we also
+ * need to observe the new update time.
+ */
+ smp_rmb();
+
+ /*
+ * If the folding window started, make sure we start writing in the
+ * next idle-delta.
+ */
+ if (!time_before(jiffies, calc_load_update))
+ idx++;
+
+ return idx & 1;
+}
+
+static inline int calc_load_read_idx(void)
+{
+ return calc_load_idx & 1;
+}
+
+void calc_load_enter_idle(void)
+{
+ struct rq *this_rq = this_rq();
long delta;
+ /*
+ * We're going into NOHZ mode, if there's any pending delta, fold it
+ * into the pending idle delta.
+ */
delta = calc_load_fold_active(this_rq);
- if (delta)
- atomic_long_add(delta, &calc_load_tasks_idle);
+ if (delta) {
+ int idx = calc_load_write_idx();
+ atomic_long_add(delta, &calc_load_idle[idx]);
+ }
}
-static long calc_load_fold_idle(void)
+void calc_load_exit_idle(void)
{
- long delta = 0;
+ struct rq *this_rq = this_rq();
+
+ /*
+ * If we're still before the sample window, we're done.
+ */
+ if (time_before(jiffies, this_rq->calc_load_update))
+ return;
/*
- * Its got a race, we don't care...
+ * We woke inside or after the sample window, this means we're already
+ * accounted through the nohz accounting, so skip the entire deal and
+ * sync up for the next window.
*/
- if (atomic_long_read(&calc_load_tasks_idle))
- delta = atomic_long_xchg(&calc_load_tasks_idle, 0);
+ this_rq->calc_load_update = calc_load_update;
+ if (time_before(jiffies, this_rq->calc_load_update + 10))
+ this_rq->calc_load_update += LOAD_FREQ;
+}
+
+static long calc_load_fold_idle(void)
+{
+ int idx = calc_load_read_idx();
+ long delta = 0;
+
+ if (atomic_long_read(&calc_load_idle[idx]))
+ delta = atomic_long_xchg(&calc_load_idle[idx], 0);
return delta;
}
{
long delta, active, n;
- /*
- * If we crossed a calc_load_update boundary, make sure to fold
- * any pending idle changes, the respective CPUs might have
- * missed the tick driven calc_load_account_active() update
- * due to NO_HZ.
- */
- delta = calc_load_fold_idle();
- if (delta)
- atomic_long_add(delta, &calc_load_tasks);
-
- /*
- * It could be the one fold was all it took, we done!
- */
- if (time_before(jiffies, calc_load_update + 10))
- return;
-
- /*
- * Catch-up, fold however many we are behind still
- */
- delta = jiffies - calc_load_update - 10;
- n = 1 + (delta / LOAD_FREQ);
+ if (!time_before(jiffies, calc_load_update + 10)) {
+ /*
+ * Catch-up, fold however many we are behind still
+ */
+ delta = jiffies - calc_load_update - 10;
+ n = 1 + (delta / LOAD_FREQ);
- active = atomic_long_read(&calc_load_tasks);
- active = active > 0 ? active * FIXED_1 : 0;
+ active = atomic_long_read(&calc_load_tasks);
+ active = active > 0 ? active * FIXED_1 : 0;
- avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
- avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
- avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
+ avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+ avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+ avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
- calc_load_update += n * LOAD_FREQ;
-}
-#else
-void calc_load_account_idle(struct rq *this_rq)
-{
-}
+ calc_load_update += n * LOAD_FREQ;
+ }
-static inline long calc_load_fold_idle(void)
-{
- return 0;
+ /*
+ * Flip the idle index...
+ *
+ * Make sure we first write the new time then flip the index, so that
+ * calc_load_write_idx() will see the new time when it reads the new
+ * index, this avoids a double flip messing things up.
+ */
+ smp_wmb();
+ calc_load_idx++;
}
+#else /* !CONFIG_NO_HZ */
-static void calc_global_nohz(void)
-{
-}
-#endif
+static inline long calc_load_fold_idle(void) { return 0; }
+static inline void calc_global_nohz(void) { }
-/**
- * get_avenrun - get the load average array
- * @loads: pointer to dest load array
- * @offset: offset to add
- * @shift: shift count to shift the result left
- *
- * These values are estimates at best, so no need for locking.
- */
-void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
-{
- loads[0] = (avenrun[0] + offset) << shift;
- loads[1] = (avenrun[1] + offset) << shift;
- loads[2] = (avenrun[2] + offset) << shift;
-}
+#endif /* CONFIG_NO_HZ */
/*
* calc_load - update the avenrun load estimates 10 ticks after the
*/
void calc_global_load(unsigned long ticks)
{
- long active;
+ long active, delta;
if (time_before(jiffies, calc_load_update + 10))
return;
+ /*
+ * Fold the 'old' idle-delta to include all NO_HZ cpus.
+ */
+ delta = calc_load_fold_idle();
+ if (delta)
+ atomic_long_add(delta, &calc_load_tasks);
+
active = atomic_long_read(&calc_load_tasks);
active = active > 0 ? active * FIXED_1 : 0;
calc_load_update += LOAD_FREQ;
/*
- * Account one period with whatever state we found before
- * folding in the nohz state and ageing the entire idle period.
- *
- * This avoids loosing a sample when we go idle between
- * calc_load_account_active() (10 ticks ago) and now and thus
- * under-accounting.
+ * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
*/
calc_global_nohz();
}
return;
delta = calc_load_fold_active(this_rq);
- delta += calc_load_fold_idle();
if (delta)
atomic_long_add(delta, &calc_load_tasks);
this_rq->calc_load_update += LOAD_FREQ;
}
+/*
+ * End of global load-average stuff
+ */
+
/*
* The exact cpuload at various idx values, calculated at every tick would be
* load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
static struct task_struct *pick_next_task_idle(struct rq *rq)
{
schedstat_inc(rq, sched_goidle);
- calc_load_account_idle(rq);
return rq->idle;
}
return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2;
}
-void calc_load_account_idle(struct rq *this_rq);
-
#ifdef CONFIG_SCHED_HRTICK
/*
#ifdef CONFIG_CHECKPOINT_RESTORE
static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
{
- struct vm_area_struct *vma;
struct file *exe_file;
struct dentry *dentry;
int err;
down_write(&mm->mmap_sem);
/*
- * Forbid mm->exe_file change if there are mapped other files.
+ * Forbid mm->exe_file change if old file still mapped.
*/
err = -EBUSY;
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (vma->vm_file && !path_equal(&vma->vm_file->f_path,
- &exe_file->f_path))
- goto exit_unlock;
+ if (mm->exe_file) {
+ struct vm_area_struct *vma;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ if (vma->vm_file &&
+ path_equal(&vma->vm_file->f_path,
+ &mm->exe_file->f_path))
+ goto exit_unlock;
}
/*
if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
goto exit_unlock;
+ err = 0;
set_mm_exe_file(mm, exe_file);
exit_unlock:
up_write(&mm->mmap_sem);
*/
if (!ts->tick_stopped) {
select_nohz_load_balancer(1);
+ calc_load_enter_idle();
ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
ts->tick_stopped = 1;
account_idle_ticks(ticks);
#endif
+ calc_load_exit_idle();
touch_softlockup_watchdog();
/*
* Cancel the scheduled timer and restore the tick
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
struct timespec raw_time;
+ /* Offset clock monotonic -> clock realtime */
+ ktime_t offs_real;
+
+ /* Offset clock monotonic -> clock boottime */
+ ktime_t offs_boot;
+
/* Seqlock for all timekeeper values */
seqlock_t lock;
};
return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
}
+static void update_rt_offset(void)
+{
+ struct timespec tmp, *wtm = &timekeeper.wall_to_monotonic;
+
+ set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec);
+ timekeeper.offs_real = timespec_to_ktime(tmp);
+}
+
/* must hold write on timekeeper.lock */
static void timekeeping_update(bool clearntp)
{
timekeeper.ntp_error = 0;
ntp_clear();
}
+ update_rt_offset();
update_vsyscall(&timekeeper.xtime, &timekeeper.wall_to_monotonic,
timekeeper.clock, timekeeper.mult);
}
}
set_normalized_timespec(&timekeeper.wall_to_monotonic,
-boot.tv_sec, -boot.tv_nsec);
+ update_rt_offset();
timekeeper.total_sleep_time.tv_sec = 0;
timekeeper.total_sleep_time.tv_nsec = 0;
write_sequnlock_irqrestore(&timekeeper.lock, flags);
/* time in seconds when suspend began */
static struct timespec timekeeping_suspend_time;
+static void update_sleep_time(struct timespec t)
+{
+ timekeeper.total_sleep_time = t;
+ timekeeper.offs_boot = timespec_to_ktime(t);
+}
+
/**
* __timekeeping_inject_sleeptime - Internal function to add sleep interval
* @delta: pointer to a timespec delta value
timekeeper.xtime = timespec_add(timekeeper.xtime, *delta);
timekeeper.wall_to_monotonic =
timespec_sub(timekeeper.wall_to_monotonic, *delta);
- timekeeper.total_sleep_time = timespec_add(
- timekeeper.total_sleep_time, *delta);
+ update_sleep_time(timespec_add(timekeeper.total_sleep_time, *delta));
}
leap = second_overflow(timekeeper.xtime.tv_sec);
timekeeper.xtime.tv_sec += leap;
timekeeper.wall_to_monotonic.tv_sec -= leap;
+ if (leap)
+ clock_was_set_delayed();
}
/* Accumulate raw time */
leap = second_overflow(timekeeper.xtime.tv_sec);
timekeeper.xtime.tv_sec += leap;
timekeeper.wall_to_monotonic.tv_sec -= leap;
+ if (leap)
+ clock_was_set_delayed();
}
timekeeping_update(false);
} while (read_seqretry(&timekeeper.lock, seq));
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/**
+ * ktime_get_update_offsets - hrtimer helper
+ * @offs_real: pointer to storage for monotonic -> realtime offset
+ * @offs_boot: pointer to storage for monotonic -> boottime offset
+ *
+ * Returns current monotonic time and updates the offsets
+ * Called from hrtimer_interupt() or retrigger_next_event()
+ */
+ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
+{
+ ktime_t now;
+ unsigned int seq;
+ u64 secs, nsecs;
+
+ do {
+ seq = read_seqbegin(&timekeeper.lock);
+
+ secs = timekeeper.xtime.tv_sec;
+ nsecs = timekeeper.xtime.tv_nsec;
+ nsecs += timekeeping_get_ns();
+ /* If arch requires, add in gettimeoffset() */
+ nsecs += arch_gettimeoffset();
+
+ *offs_real = timekeeper.offs_real;
+ *offs_boot = timekeeper.offs_boot;
+ } while (read_seqretry(&timekeeper.lock, seq));
+
+ now = ktime_add_ns(ktime_set(secs, 0), nsecs);
+ now = ktime_sub(now, *offs_real);
+ return now;
+}
+#endif
+
/**
* ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format
*/
rb_init_page(bpage->page);
INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
ret = rb_allocate_pages(cpu_buffer, nr_pages);
if (ret < 0)
* If something was added to this page, it was full
* since it is not the tail page. So we deduct the
* bytes consumed in ring buffer from here.
- * No need to update overruns, since this page is
- * deleted from ring buffer and its entries are
- * already accounted for.
+ * Increment overrun to account for the lost events.
*/
+ local_add(page_entries, &cpu_buffer->overrun);
local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
}
.pages = pages_def,
.partial = partial_def,
.nr_pages = 0, /* This gets updated below. */
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &tracing_pipe_buf_ops,
.spd_release = tracing_spd_release_pipe,
ret = splice_to_pipe(pipe, &spd);
out:
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
return ret;
out_err:
struct splice_pipe_desc spd = {
.pages = pages_def,
.partial = partial_def,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &buffer_pipe_buf_ops,
.spd_release = buffer_spd_release,
}
ret = splice_to_pipe(pipe, &spd);
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
out:
return ret;
}
static DEFINE_SPINLOCK(free_entries_lock);
/* Global disable flag - will be set in case of an error */
-static bool global_disable __read_mostly;
+static u32 global_disable __read_mostly;
/* Global error count */
static u32 error_count;
global_disable_dent = debugfs_create_bool("disabled", 0444,
dma_debug_dent,
- (u32 *)&global_disable);
+ &global_disable);
if (!global_disable_dent)
goto out_err;
return ___alloc_bootmem(size, align, goal, limit);
}
-static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size, unsigned long align,
unsigned long goal, unsigned long limit)
{
if (err) {
putback_lru_pages(&cc->migratepages);
cc->nr_migratepages = 0;
+ if (err == -ENOMEM) {
+ ret = COMPACT_PARTIAL;
+ goto out;
+ }
}
-
}
out:
#include <linux/sched.h>
#include <linux/ksm.h>
#include <linux/fs.h>
+#include <linux/file.h>
/*
* Any behaviour which results in changes to the vma->vm_flags needs to
{
loff_t offset;
int error;
+ struct file *f;
*prev = NULL; /* tell sys_madvise we drop mmap_sem */
if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))
return -EINVAL;
- if (!vma->vm_file || !vma->vm_file->f_mapping
- || !vma->vm_file->f_mapping->host) {
+ f = vma->vm_file;
+
+ if (!f || !f->f_mapping || !f->f_mapping->host) {
return -EINVAL;
}
offset = (loff_t)(start - vma->vm_start)
+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
- /* filesystem's fallocate may need to take i_mutex */
+ /*
+ * Filesystem's fallocate may need to take i_mutex. We need to
+ * explicitly grab a reference because the vma (and hence the
+ * vma's reference to the file) can go away as soon as we drop
+ * mmap_sem.
+ */
+ get_file(f);
up_read(¤t->mm->mmap_sem);
- error = do_fallocate(vma->vm_file,
+ error = do_fallocate(f,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset, end - start);
+ fput(f);
down_read(¤t->mm->mmap_sem);
return error;
}
MAX_NUMNODES);
}
-/*
- * Free memblock.reserved.regions
- */
-int __init_memblock memblock_free_reserved_regions(void)
-{
- if (memblock.reserved.regions == memblock_reserved_init_regions)
- return 0;
-
- return memblock_free(__pa(memblock.reserved.regions),
- sizeof(struct memblock_region) * memblock.reserved.max);
-}
-
-/*
- * Reserve memblock.reserved.regions
- */
-int __init_memblock memblock_reserve_reserved_regions(void)
-{
- if (memblock.reserved.regions == memblock_reserved_init_regions)
- return 0;
-
- return memblock_reserve(__pa(memblock.reserved.regions),
- sizeof(struct memblock_region) * memblock.reserved.max);
-}
-
static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
{
type->total_size -= type->regions[r].size;
}
}
+phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
+ phys_addr_t *addr)
+{
+ if (memblock.reserved.regions == memblock_reserved_init_regions)
+ return 0;
+
+ *addr = __pa(memblock.reserved.regions);
+
+ return PAGE_ALIGN(sizeof(struct memblock_region) *
+ memblock.reserved.max);
+}
+
/**
* memblock_double_array - double the size of the memblock regions array
* @type: memblock type of the regions array being doubled
phys_addr_t new_area_size)
{
struct memblock_region *new_array, *old_array;
+ phys_addr_t old_alloc_size, new_alloc_size;
phys_addr_t old_size, new_size, addr;
int use_slab = slab_is_available();
int *in_slab;
/* Calculate new doubled size */
old_size = type->max * sizeof(struct memblock_region);
new_size = old_size << 1;
+ /*
+ * We need to allocated new one align to PAGE_SIZE,
+ * so we can free them completely later.
+ */
+ old_alloc_size = PAGE_ALIGN(old_size);
+ new_alloc_size = PAGE_ALIGN(new_size);
/* Retrieve the slab flag */
if (type == &memblock.memory)
addr = memblock_find_in_range(new_area_start + new_area_size,
memblock.current_limit,
- new_size, sizeof(phys_addr_t));
+ new_alloc_size, PAGE_SIZE);
if (!addr && new_area_size)
addr = memblock_find_in_range(0,
min(new_area_start, memblock.current_limit),
- new_size, sizeof(phys_addr_t));
+ new_alloc_size, PAGE_SIZE);
new_array = addr ? __va(addr) : 0;
}
kfree(old_array);
else if (old_array != memblock_memory_init_regions &&
old_array != memblock_reserved_init_regions)
- memblock_free(__pa(old_array), old_size);
+ memblock_free(__pa(old_array), old_alloc_size);
/* Reserve the new array if that comes from the memblock.
* Otherwise, we needn't do it
*/
if (!use_slab)
- BUG_ON(memblock_reserve(addr, new_size));
+ BUG_ON(memblock_reserve(addr, new_alloc_size));
/* Update slab flag */
*in_slab = use_slab;
pgdat = hotadd_new_pgdat(nid, start);
ret = -ENOMEM;
if (!pgdat)
- goto out;
+ goto error;
new_pgdat = 1;
}
__free_pages_bootmem(pfn_to_page(i), 0);
}
+static unsigned long __init __free_memory_core(phys_addr_t start,
+ phys_addr_t end)
+{
+ unsigned long start_pfn = PFN_UP(start);
+ unsigned long end_pfn = min_t(unsigned long,
+ PFN_DOWN(end), max_low_pfn);
+
+ if (start_pfn > end_pfn)
+ return 0;
+
+ __free_pages_memory(start_pfn, end_pfn);
+
+ return end_pfn - start_pfn;
+}
+
unsigned long __init free_low_memory_core_early(int nodeid)
{
unsigned long count = 0;
- phys_addr_t start, end;
+ phys_addr_t start, end, size;
u64 i;
- /* free reserved array temporarily so that it's treated as free area */
- memblock_free_reserved_regions();
-
- for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL) {
- unsigned long start_pfn = PFN_UP(start);
- unsigned long end_pfn = min_t(unsigned long,
- PFN_DOWN(end), max_low_pfn);
- if (start_pfn < end_pfn) {
- __free_pages_memory(start_pfn, end_pfn);
- count += end_pfn - start_pfn;
- }
- }
+ for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL)
+ count += __free_memory_core(start, end);
+
+ /* free range that is used for reserved array if we allocate it */
+ size = get_allocated_memblock_reserved_regions_info(&start);
+ if (size)
+ count += __free_memory_core(start, start + size);
- /* put region array back? */
- memblock_reserve_reserved_regions();
return count;
}
return ___alloc_bootmem(size, align, goal, limit);
}
-static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
unsigned long size,
unsigned long align,
unsigned long goal,
return 0;
}
+/*
+ * Sometimes, before we decide whether to proceed or to fail, we must check
+ * that an entry was not already brought back from swap by a racing thread.
+ *
+ * Checking page is not enough: by the time a SwapCache page is locked, it
+ * might be reused, and again be SwapCache, using the same swap as before.
+ */
+static bool shmem_confirm_swap(struct address_space *mapping,
+ pgoff_t index, swp_entry_t swap)
+{
+ void *item;
+
+ rcu_read_lock();
+ item = radix_tree_lookup(&mapping->page_tree, index);
+ rcu_read_unlock();
+ return item == swp_to_radix_entry(swap);
+}
+
/*
* Like add_to_page_cache_locked, but error if expected item has gone.
*/
struct address_space *mapping,
pgoff_t index, gfp_t gfp, void *expected)
{
- int error = 0;
+ int error;
VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(!PageSwapBacked(page));
+ page_cache_get(page);
+ page->mapping = mapping;
+ page->index = index;
+
+ spin_lock_irq(&mapping->tree_lock);
if (!expected)
- error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+ error = radix_tree_insert(&mapping->page_tree, index, page);
+ else
+ error = shmem_radix_tree_replace(mapping, index, expected,
+ page);
if (!error) {
- page_cache_get(page);
- page->mapping = mapping;
- page->index = index;
-
- spin_lock_irq(&mapping->tree_lock);
- if (!expected)
- error = radix_tree_insert(&mapping->page_tree,
- index, page);
- else
- error = shmem_radix_tree_replace(mapping, index,
- expected, page);
- if (!error) {
- mapping->nrpages++;
- __inc_zone_page_state(page, NR_FILE_PAGES);
- __inc_zone_page_state(page, NR_SHMEM);
- spin_unlock_irq(&mapping->tree_lock);
- } else {
- page->mapping = NULL;
- spin_unlock_irq(&mapping->tree_lock);
- page_cache_release(page);
- }
- if (!expected)
- radix_tree_preload_end();
+ mapping->nrpages++;
+ __inc_zone_page_state(page, NR_FILE_PAGES);
+ __inc_zone_page_state(page, NR_SHMEM);
+ spin_unlock_irq(&mapping->tree_lock);
+ } else {
+ page->mapping = NULL;
+ spin_unlock_irq(&mapping->tree_lock);
+ page_cache_release(page);
}
- if (error)
- mem_cgroup_uncharge_cache_page(page);
return error;
}
/* We have to do this with page locked to prevent races */
lock_page(page);
if (!PageSwapCache(page) || page_private(page) != swap.val ||
- page->mapping) {
+ !shmem_confirm_swap(mapping, index, swap)) {
error = -EEXIST; /* try again */
- goto failed;
+ goto unlock;
}
if (!PageUptodate(page)) {
error = -EIO;
error = mem_cgroup_cache_charge(page, current->mm,
gfp & GFP_RECLAIM_MASK);
- if (!error)
+ if (!error) {
error = shmem_add_to_page_cache(page, mapping, index,
gfp, swp_to_radix_entry(swap));
+ /* We already confirmed swap, and make no allocation */
+ VM_BUG_ON(error);
+ }
if (error)
goto failed;
__set_page_locked(page);
error = mem_cgroup_cache_charge(page, current->mm,
gfp & GFP_RECLAIM_MASK);
- if (!error)
- error = shmem_add_to_page_cache(page, mapping, index,
- gfp, NULL);
if (error)
goto decused;
+ error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+ if (!error) {
+ error = shmem_add_to_page_cache(page, mapping, index,
+ gfp, NULL);
+ radix_tree_preload_end();
+ }
+ if (error) {
+ mem_cgroup_uncharge_cache_page(page);
+ goto decused;
+ }
lru_cache_add_anon(page);
spin_lock(&info->lock);
unacct:
shmem_unacct_blocks(info->flags, 1);
failed:
- if (swap.val && error != -EINVAL) {
- struct page *test = find_get_page(mapping, index);
- if (test && !radix_tree_exceptional_entry(test))
- page_cache_release(test);
- /* Have another try if the entry has changed */
- if (test != swp_to_radix_entry(swap))
- error = -EEXIST;
- }
+ if (swap.val && error != -EINVAL &&
+ !shmem_confirm_swap(mapping, index, swap))
+ error = -EEXIST;
+unlock:
if (page) {
unlock_page(page);
page_cache_release(page);
spin_unlock(&info->lock);
goto repeat;
}
- if (error == -EEXIST)
+ if (error == -EEXIST) /* from above or from radix_tree_insert */
goto repeat;
return error;
}
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
+ .nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &page_cache_pipe_buf_ops,
.spd_release = spd_release_page,
if (spd.nr_pages)
error = splice_to_pipe(pipe, &spd);
- splice_shrink_spd(pipe, &spd);
+ splice_shrink_spd(&spd);
if (error > 0) {
*ppos += error;
return error;
}
-/*
- * llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
- */
-static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
- pgoff_t index, pgoff_t end, int origin)
-{
- struct page *page;
- struct pagevec pvec;
- pgoff_t indices[PAGEVEC_SIZE];
- bool done = false;
- int i;
-
- pagevec_init(&pvec, 0);
- pvec.nr = 1; /* start small: we may be there already */
- while (!done) {
- pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
- pvec.nr, pvec.pages, indices);
- if (!pvec.nr) {
- if (origin == SEEK_DATA)
- index = end;
- break;
- }
- for (i = 0; i < pvec.nr; i++, index++) {
- if (index < indices[i]) {
- if (origin == SEEK_HOLE) {
- done = true;
- break;
- }
- index = indices[i];
- }
- page = pvec.pages[i];
- if (page && !radix_tree_exceptional_entry(page)) {
- if (!PageUptodate(page))
- page = NULL;
- }
- if (index >= end ||
- (page && origin == SEEK_DATA) ||
- (!page && origin == SEEK_HOLE)) {
- done = true;
- break;
- }
- }
- shmem_deswap_pagevec(&pvec);
- pagevec_release(&pvec);
- pvec.nr = PAGEVEC_SIZE;
- cond_resched();
- }
- return index;
-}
-
-static loff_t shmem_file_llseek(struct file *file, loff_t offset, int origin)
-{
- struct address_space *mapping;
- struct inode *inode;
- pgoff_t start, end;
- loff_t new_offset;
-
- if (origin != SEEK_DATA && origin != SEEK_HOLE)
- return generic_file_llseek_size(file, offset, origin,
- MAX_LFS_FILESIZE);
- mapping = file->f_mapping;
- inode = mapping->host;
- mutex_lock(&inode->i_mutex);
- /* We're holding i_mutex so we can access i_size directly */
-
- if (offset < 0)
- offset = -EINVAL;
- else if (offset >= inode->i_size)
- offset = -ENXIO;
- else {
- start = offset >> PAGE_CACHE_SHIFT;
- end = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- new_offset = shmem_seek_hole_data(mapping, start, end, origin);
- new_offset <<= PAGE_CACHE_SHIFT;
- if (new_offset > offset) {
- if (new_offset < inode->i_size)
- offset = new_offset;
- else if (origin == SEEK_DATA)
- offset = -ENXIO;
- else
- offset = inode->i_size;
- }
- }
-
- if (offset >= 0 && offset != file->f_pos) {
- file->f_pos = offset;
- file->f_version = 0;
- }
- mutex_unlock(&inode->i_mutex);
- return offset;
-}
-
static long shmem_fallocate(struct file *file, int mode, loff_t offset,
loff_t len)
{
static const struct file_operations shmem_file_operations = {
.mmap = shmem_mmap,
#ifdef CONFIG_TMPFS
- .llseek = shmem_file_llseek,
+ .llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = shmem_file_aio_read,
sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
unsigned long size)
{
- pg_data_t *host_pgdat;
- unsigned long goal;
+ unsigned long goal, limit;
+ unsigned long *p;
+ int nid;
/*
* A page may contain usemaps for other sections preventing the
* page being freed and making a section unremovable while
* from the same section as the pgdat where possible to avoid
* this problem.
*/
- goal = __pa(pgdat) & PAGE_SECTION_MASK;
- host_pgdat = NODE_DATA(early_pfn_to_nid(goal >> PAGE_SHIFT));
- return __alloc_bootmem_node_nopanic(host_pgdat, size,
- SMP_CACHE_BYTES, goal);
+ goal = __pa(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
+ limit = goal + (1UL << PA_SECTION_SHIFT);
+ nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
+again:
+ p = ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size,
+ SMP_CACHE_BYTES, goal, limit);
+ if (!p && limit) {
+ limit = 0;
+ goto again;
+ }
+ return p;
}
static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
}
/*
- * Called by memory hotplug when all memory in a node is offlined.
+ * Called by memory hotplug when all memory in a node is offlined. Caller must
+ * hold lock_memory_hotplug().
*/
void kswapd_stop(int nid)
{
struct task_struct *kswapd = NODE_DATA(nid)->kswapd;
- if (kswapd)
+ if (kswapd) {
kthread_stop(kswapd);
+ NODE_DATA(nid)->kswapd = NULL;
+ }
}
static int __init kswapd_init(void)
no_module = request_module("netdev-%s", name);
if (no_module && capable(CAP_SYS_MODULE)) {
if (!request_module("%s", name))
- pr_err("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
- name);
+ pr_warn("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
+ name);
}
}
EXPORT_SYMBOL(dev_load);
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
+ .nr_pages_max = MAX_SKB_FRAGS,
.flags = flags,
.ops = &sock_pipe_buf_ops,
.spd_release = sock_spd_release,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0;
- u8 bssid[ETH_ALEN];
ASSERT_MGD_MTX(ifmgd);
ieee80211_stop_poll(sdata);
- memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
-
ifmgd->associated = NULL;
- memset(ifmgd->bssid, 0, ETH_ALEN);
/*
* we need to commit the associated = NULL change because the
netif_carrier_off(sdata->dev);
mutex_lock(&local->sta_mtx);
- sta = sta_info_get(sdata, bssid);
+ sta = sta_info_get(sdata, ifmgd->bssid);
if (sta) {
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta, tx);
/* deauthenticate/disassociate now */
if (tx || frame_buf)
- ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason,
- tx, frame_buf);
+ ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
+ reason, tx, frame_buf);
/* flush out frame */
if (tx)
drv_flush(local, false);
+ /* clear bssid only after building the needed mgmt frames */
+ memset(ifmgd->bssid, 0, ETH_ALEN);
+
/* remove AP and TDLS peers */
sta_info_flush(local, sdata);
* frames that we didn't handle, including returning unknown
* ones. For all other modes we will return them to the sender,
* setting the 0x80 bit in the action category, as required by
- * 802.11-2007 7.3.1.11.
+ * 802.11-2012 9.24.4.
* Newer versions of hostapd shall also use the management frame
* registration mechanisms, but older ones still use cooked
* monitor interfaces so push all frames there.
sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
return RX_DROP_MONITOR;
+ if (is_multicast_ether_addr(mgmt->da))
+ return RX_DROP_MONITOR;
+
/* do not return rejected action frames */
if (mgmt->u.action.category & 0x80)
return RX_DROP_UNUSABLE;
return 0;
}
+static int
+ip_set_none(struct sock *ctnl, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const attr[])
+{
+ return -EOPNOTSUPP;
+}
+
static int
ip_set_create(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
}
static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
+ [IPSET_CMD_NONE] = {
+ .call = ip_set_none,
+ .attr_count = IPSET_ATTR_CMD_MAX,
+ },
[IPSET_CMD_CREATE] = {
.call = ip_set_create,
.attr_count = IPSET_ATTR_CMD_MAX,
#define iface_data(n) (rb_entry(n, struct iface_node, node)->iface)
-static inline long
-ifname_compare(const char *_a, const char *_b)
-{
- const long *a = (const long *)_a;
- const long *b = (const long *)_b;
-
- BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
- if (a[0] != b[0])
- return a[0] - b[0];
- if (IFNAMSIZ > sizeof(long)) {
- if (a[1] != b[1])
- return a[1] - b[1];
- }
- if (IFNAMSIZ > 2 * sizeof(long)) {
- if (a[2] != b[2])
- return a[2] - b[2];
- }
- if (IFNAMSIZ > 3 * sizeof(long)) {
- if (a[3] != b[3])
- return a[3] - b[3];
- }
- return 0;
-}
-
static void
rbtree_destroy(struct rb_root *root)
{
while (n) {
const char *d = iface_data(n);
- long res = ifname_compare(*iface, d);
+ int res = strcmp(*iface, d);
if (res < 0)
n = n->rb_left;
while (*n) {
char *ifname = iface_data(*n);
- long res = ifname_compare(*iface, ifname);
+ int res = strcmp(*iface, ifname);
p = *n;
if (res < 0)
struct hash_netiface4_elem data = { .cidr = HOST_MASK };
u32 ip = 0, ip_to, last;
u32 timeout = h->timeout;
- char iface[IFNAMSIZ] = {};
+ char iface[IFNAMSIZ];
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
- char iface[IFNAMSIZ] = {};
+ char iface[IFNAMSIZ];
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
#ifdef CONFIG_IP_VS_IPV6
/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
-static int __ip_vs_addr_is_local_v6(struct net *net,
- const struct in6_addr *addr)
+static bool __ip_vs_addr_is_local_v6(struct net *net,
+ const struct in6_addr *addr)
{
- struct rt6_info *rt;
struct flowi6 fl6 = {
.daddr = *addr,
};
+ struct dst_entry *dst = ip6_route_output(net, NULL, &fl6);
+ bool is_local;
- rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
- if (rt && rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
- return 1;
+ is_local = !dst->error && dst->dev && (dst->dev->flags & IFF_LOOPBACK);
- return 0;
+ dst_release(dst);
+ return is_local;
}
#endif
err = nla_parse(cda, ss->cb[cb_id].attr_count,
attr, attrlen, ss->cb[cb_id].policy);
- if (err < 0)
+ if (err < 0) {
+ rcu_read_unlock();
return err;
+ }
if (nc->call_rcu) {
err = nc->call_rcu(net->nfnl, skb, nlh,
nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
data += 2;
- nfca_poll->nfcid1_len = *data++;
+ nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE);
pr_debug("sens_res 0x%x, nfcid1_len %d\n",
nfca_poll->sens_res, nfca_poll->nfcid1_len);
struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
__u8 *data)
{
- nfcb_poll->sensb_res_len = *data++;
+ nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE);
pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
__u8 *data)
{
nfcf_poll->bit_rate = *data++;
- nfcf_poll->sensf_res_len = *data++;
+ nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);
pr_debug("bit_rate %d, sensf_res_len %d\n",
nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
switch (ntf->activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
- nfca_poll->rats_res_len = *data++;
+ nfca_poll->rats_res_len = min_t(__u8, *data++, 20);
pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
if (nfca_poll->rats_res_len > 0) {
memcpy(nfca_poll->rats_res,
case NCI_NFC_B_PASSIVE_POLL_MODE:
nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
- nfcb_poll->attrib_res_len = *data++;
+ nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50);
pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
if (nfcb_poll->attrib_res_len > 0) {
memcpy(nfcb_poll->attrib_res,
{
struct sock *sk = sock->sk;
- pr_debug("sock=%p\n", sock);
+ pr_debug("sock=%p sk=%p\n", sock, sk);
+
+ if (!sk)
+ return 0;
sock_orphan(sk);
sock_put(sk);
*/
asoc->peer.sack_needed = 1;
asoc->peer.sack_cnt = 0;
+ asoc->peer.sack_generation = 1;
/* Assume that the peer will tell us if he recognizes ASCONF
* as part of INIT exchange.
/* If the SACK timer is running, we have a pending SACK */
if (timer_pending(timer)) {
struct sctp_chunk *sack;
+
+ if (pkt->transport->sack_generation !=
+ pkt->transport->asoc->peer.sack_generation)
+ return retval;
+
asoc->a_rwnd = asoc->rwnd;
sack = sctp_make_sack(asoc);
if (sack) {
int len;
__u32 ctsn;
__u16 num_gabs, num_dup_tsns;
+ struct sctp_association *aptr = (struct sctp_association *)asoc;
struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+ struct sctp_transport *trans;
memset(gabs, 0, sizeof(gabs));
ctsn = sctp_tsnmap_get_ctsn(map);
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map));
+ /* Once we have a sack generated, check to see what our sack
+ * generation is, if its 0, reset the transports to 0, and reset
+ * the association generation to 1
+ *
+ * The idea is that zero is never used as a valid generation for the
+ * association so no transport will match after a wrap event like this,
+ * Until the next sack
+ */
+ if (++aptr->peer.sack_generation == 0) {
+ list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+ transports)
+ trans->sack_generation = 0;
+ aptr->peer.sack_generation = 1;
+ }
nodata:
return retval;
}
case SCTP_CMD_REPORT_TSN:
/* Record the arrival of a TSN. */
error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
- cmd->obj.u32);
+ cmd->obj.u32, NULL);
break;
case SCTP_CMD_REPORT_FWDTSN:
peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
memset(&peer->saddr, 0, sizeof(union sctp_addr));
+ peer->sack_generation = 0;
+
/* From 6.3.1 RTO Calculation:
*
* C1) Until an RTT measurement has been made for a packet sent to the
/* Mark this TSN as seen. */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+ struct sctp_transport *trans)
{
u16 gap;
*/
map->max_tsn_seen++;
map->cumulative_tsn_ack_point++;
+ if (trans)
+ trans->sack_generation =
+ trans->asoc->peer.sack_generation;
map->base_tsn++;
} else {
/* Either we already have a gap, or about to record a gap, so
* can mark it as received so the tsn_map is updated correctly.
*/
if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
- ntohl(chunk->subh.data_hdr->tsn)))
+ ntohl(chunk->subh.data_hdr->tsn),
+ chunk->transport))
goto fail_mark;
/* First calculate the padding, so we don't inadvertently
if (chunk && (freed >= needed)) {
__u32 tsn;
tsn = ntohl(chunk->subh.data_hdr->tsn);
- sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+ sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
sctp_ulpq_tail_data(ulpq, chunk, gfp);
sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
#include <linux/mman.h>
#include <linux/mount.h>
#include <linux/personality.h>
+#include <linux/backing-dev.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
{}
};
+static void alc662_fill_coef(struct hda_codec *codec)
+{
+ int val, coef;
+
+ coef = alc_get_coef0(codec);
+
+ switch (codec->vendor_id) {
+ case 0x10ec0662:
+ if ((coef & 0x00f0) == 0x0030) {
+ val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */
+ alc_write_coef_idx(codec, 0x4, val & ~(1<<10));
+ }
+ break;
+ case 0x10ec0272:
+ case 0x10ec0273:
+ case 0x10ec0663:
+ case 0x10ec0665:
+ case 0x10ec0670:
+ case 0x10ec0671:
+ case 0x10ec0672:
+ val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */
+ alc_write_coef_idx(codec, 0xd, val | (1<<14));
+ break;
+ }
+}
/*
*/
alc_fix_pll_init(codec, 0x20, 0x04, 15);
+ spec->init_hook = alc662_fill_coef;
+ alc662_fill_coef(codec);
+
alc_pick_fixup(codec, alc662_fixup_models,
alc662_fixup_tbl, alc662_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
}
found:
- data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
- snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
- data | (pll_p << PLLP_SHIFT));
+ snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
pll_r << PLLR_SHIFT);
snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
/* PLL registers bitfields */
#define PLLP_SHIFT 0
+#define PLLP_MASK 7
#define PLLQ_SHIFT 3
#define PLLR_SHIFT 0
#define PLLJ_SHIFT 2
static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
5644800,
+ 3763200,
2882400,
1881600,
1411200,
{
struct list_head *p;
struct snd_usb_endpoint *ep;
- int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+ int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
mutex_lock(&chip->mutex);
type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
ep_num);
- /* select the alt setting once so the endpoints become valid */
- ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
- alts->desc.bAlternateSetting);
- if (ret < 0) {
- snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
- __func__, ret);
- ep = NULL;
- goto __exit_unlock;
- }
-
ep = kzalloc(sizeof(*ep), GFP_KERNEL);
if (!ep)
goto __exit_unlock;
if (++ep->use_count != 1)
return 0;
- if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
- return -EINVAL;
-
/* just to be sure */
deactivate_urbs(ep, 0, 1);
wait_clear_urbs(ep);
if (snd_BUG_ON(ep->use_count == 0))
return;
- if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
- return;
-
if (--ep->use_count == 0) {
deactivate_urbs(ep, force, can_sleep);
ep->data_subs = NULL;
}
}
-/**
- * snd_usb_endpoint_activate: activate an snd_usb_endpoint
- *
- * @ep: the endpoint to activate
- *
- * If the endpoint is not currently in use, this functions will select the
- * correct alternate interface setting for the interface of this endpoint.
- *
- * In case of any active users, this functions does nothing.
- *
- * Returns an error if usb_set_interface() failed, 0 in all other
- * cases.
- */
-int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
-{
- if (ep->use_count != 0)
- return 0;
-
- if (!ep->chip->shutdown &&
- !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
- int ret;
-
- ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
- if (ret < 0) {
- snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
- __func__, ret);
- clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
- return ret;
- }
-
- return 0;
- }
-
- return -EBUSY;
-}
-
/**
* snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
*
if (!ep)
return -EINVAL;
+ deactivate_urbs(ep, 1, 1);
+ wait_clear_urbs(ep);
+
if (ep->use_count != 0)
return 0;
- if (!ep->chip->shutdown &&
- test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
- int ret;
-
- ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
- if (ret < 0) {
- snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
- __func__, ret);
- return ret;
- }
+ clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
- return 0;
- }
-
- return -EBUSY;
+ return 0;
}
/**
force, can_sleep, wait);
}
-static int activate_endpoints(struct snd_usb_substream *subs)
-{
- if (subs->sync_endpoint) {
- int ret;
-
- ret = snd_usb_endpoint_activate(subs->sync_endpoint);
- if (ret < 0)
- return ret;
- }
-
- return snd_usb_endpoint_activate(subs->data_endpoint);
-}
-
static int deactivate_endpoints(struct snd_usb_substream *subs)
{
int reta, retb;
if (fmt == subs->cur_audiofmt)
return 0;
+ /* close the old interface */
+ if (subs->interface >= 0 && subs->interface != fmt->iface) {
+ err = usb_set_interface(subs->dev, subs->interface, 0);
+ if (err < 0) {
+ snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed (%d)\n",
+ dev->devnum, fmt->iface, fmt->altsetting, err);
+ return -EIO;
+ }
+ subs->interface = -1;
+ subs->altset_idx = 0;
+ }
+
+ /* set interface */
+ if (subs->interface != fmt->iface ||
+ subs->altset_idx != fmt->altset_idx) {
+ err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
+ if (err < 0) {
+ snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed (%d)\n",
+ dev->devnum, fmt->iface, fmt->altsetting, err);
+ return -EIO;
+ }
+ snd_printdd(KERN_INFO "setting usb interface %d:%d\n",
+ fmt->iface, fmt->altsetting);
+ subs->interface = fmt->iface;
+ subs->altset_idx = fmt->altset_idx;
+ }
+
subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, fmt->endpoint, subs->direction,
SND_USB_ENDPOINT_TYPE_DATA);
subs->data_endpoint->sync_master = subs->sync_endpoint;
}
- if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
+ if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0)
return err;
subs->cur_audiofmt = fmt;
struct usb_interface *iface;
iface = usb_ifnum_to_if(subs->dev, fmt->iface);
alts = &iface->altsetting[fmt->altset_idx];
- ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate);
+ ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
if (ret < 0)
return ret;
subs->cur_rate = rate;
mutex_lock(&subs->stream->chip->shutdown_mutex);
/* format changed */
stop_endpoints(subs, 0, 0, 0);
- deactivate_endpoints(subs);
-
- ret = activate_endpoints(subs);
- if (ret < 0)
- goto unlock;
-
ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
subs->sync_endpoint);
if (ret < 0)
subs->period_bytes = 0;
mutex_lock(&subs->stream->chip->shutdown_mutex);
stop_endpoints(subs, 0, 1, 1);
+ deactivate_endpoints(subs);
mutex_unlock(&subs->stream->chip->shutdown_mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
{
- int ret;
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
struct snd_usb_substream *subs = &as->substream[direction];
stop_endpoints(subs, 0, 0, 0);
- ret = deactivate_endpoints(subs);
+
+ if (!as->chip->shutdown && subs->interface >= 0) {
+ usb_set_interface(subs->dev, subs->interface, 0);
+ subs->interface = -1;
+ }
+
subs->pcm_substream = NULL;
snd_usb_autosuspend(subs->stream->chip);
- return ret;
+ return 0;
}
/* Since a URB can handle only a single linear buffer, we must use double
struct machine *machines__findnew(struct rb_root *self, pid_t pid)
{
char path[PATH_MAX];
- const char *root_dir;
+ const char *root_dir = "";
struct machine *machine = machines__find(self, pid);
- if (!machine || machine->pid != pid) {
- if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
- root_dir = "";
- else {
- if (!symbol_conf.guestmount)
- goto out;
- sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
- if (access(path, R_OK)) {
- pr_err("Can't access file %s\n", path);
- goto out;
- }
- root_dir = path;
+ if (machine && (machine->pid == pid))
+ goto out;
+
+ if ((pid != HOST_KERNEL_ID) &&
+ (pid != DEFAULT_GUEST_KERNEL_ID) &&
+ (symbol_conf.guestmount)) {
+ sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
+ if (access(path, R_OK)) {
+ pr_err("Can't access file %s\n", path);
+ machine = NULL;
+ goto out;
}
- machine = machines__add(self, pid, root_dir);
+ root_dir = path;
}
+ machine = machines__add(self, pid, root_dir);
+
out:
return machine;
}
else
pid = event->ip.pid;
- return perf_session__find_machine(session, pid);
+ return perf_session__findnew_machine(session, pid);
}
return perf_session__find_host_machine(session);
record.data = data;
trace_seq_init(&s);
- pevent_print_event(pevent, &s, &record);
+ pevent_event_info(&s, event, &record);
trace_seq_do_printf(&s);
- printf("\n");
}
void print_event(int cpu, void *data, int size, unsigned long long nsecs,
}
#ifdef __KVM_HAVE_MSI
+static irqreturn_t kvm_assigned_dev_msi(int irq, void *dev_id)
+{
+ return IRQ_WAKE_THREAD;
+}
+
static int assigned_device_enable_host_msi(struct kvm *kvm,
struct kvm_assigned_dev_kernel *dev)
{
}
dev->host_irq = dev->dev->irq;
- if (request_threaded_irq(dev->host_irq, NULL,
+ if (request_threaded_irq(dev->host_irq, kvm_assigned_dev_msi,
kvm_assigned_dev_thread_msi, 0,
dev->irq_name, dev)) {
pci_disable_msi(dev->dev);
#endif
#ifdef __KVM_HAVE_MSIX
+static irqreturn_t kvm_assigned_dev_msix(int irq, void *dev_id)
+{
+ return IRQ_WAKE_THREAD;
+}
+
static int assigned_device_enable_host_msix(struct kvm *kvm,
struct kvm_assigned_dev_kernel *dev)
{
for (i = 0; i < dev->entries_nr; i++) {
r = request_threaded_irq(dev->host_msix_entries[i].vector,
- NULL, kvm_assigned_dev_thread_msix,
+ kvm_assigned_dev_msix,
+ kvm_assigned_dev_thread_msix,
0, dev->irq_name, dev);
if (r)
goto err;
}
static int
-kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
+kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
{
struct kvm_irq_routing_table *irq_rt;
struct _irqfd *irqfd, *tmp;
return -ENOMEM;
irqfd->kvm = kvm;
- irqfd->gsi = gsi;
+ irqfd->gsi = args->gsi;
INIT_LIST_HEAD(&irqfd->list);
INIT_WORK(&irqfd->inject, irqfd_inject);
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
- file = eventfd_fget(fd);
+ file = eventfd_fget(args->fd);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto fail;
* shutdown any irqfd's that match fd+gsi
*/
static int
-kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
+kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
{
struct _irqfd *irqfd, *tmp;
struct eventfd_ctx *eventfd;
- eventfd = eventfd_ctx_fdget(fd);
+ eventfd = eventfd_ctx_fdget(args->fd);
if (IS_ERR(eventfd))
return PTR_ERR(eventfd);
spin_lock_irq(&kvm->irqfds.lock);
list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) {
- if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) {
+ if (irqfd->eventfd == eventfd && irqfd->gsi == args->gsi) {
/*
* This rcu_assign_pointer is needed for when
* another thread calls kvm_irq_routing_update before
}
int
-kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
{
- if (flags & KVM_IRQFD_FLAG_DEASSIGN)
- return kvm_irqfd_deassign(kvm, fd, gsi);
+ if (args->flags & ~KVM_IRQFD_FLAG_DEASSIGN)
+ return -EINVAL;
+
+ if (args->flags & KVM_IRQFD_FLAG_DEASSIGN)
+ return kvm_irqfd_deassign(kvm, args);
- return kvm_irqfd_assign(kvm, fd, gsi);
+ return kvm_irqfd_assign(kvm, args);
}
/*
r = -EFAULT;
if (copy_from_user(&data, argp, sizeof data))
goto out;
- r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
+ r = kvm_irqfd(kvm, &data);
break;
}
case KVM_IOEVENTFD: {
kvm_arch_hardware_unsetup();
kvm_arch_exit();
free_cpumask_var(cpus_hardware_enabled);
+ __free_page(fault_page);
__free_page(hwpoison_page);
__free_page(bad_page);
}