Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cce6fbcb authored by Subhash Jadavani's avatar Subhash Jadavani Committed by Kyle Yan
Browse files

ufs: snapshot of UFS driver



This is a snapshot of UFS driver (host controller and PHY) taken as of
msm-4.4 commit <33ec44fb> ("cfg80211: Advertise extended capabilities per
interface type to userspace").

Snapshot is taken of following files:
	drivers/scsi/ufs/*
	drivers/phy/phy-qcom-ufs*
	drivers/phy/Makefile
	include/linux/phy/phy-qcom-ufs.h
	include/uapi/scsi/ufs/*
	include/trace/events/ufs.h
	Documentation/scsi/ufs.txt
	Documentation/devicetree/bindings/ufs/*

Fixed some of the minor compilation errrors after taking the snapshot.

Change-Id: Ica7946230a37329560ad1e4667436e584228934f
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent 7e4fbe38
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -8,7 +8,8 @@ contain a phandle reference to UFS PHY node.

Required properties:
- compatible        : compatible list, contains "qcom,ufs-phy-qmp-20nm"
		      or "qcom,ufs-phy-qmp-14nm" according to the relevant phy in use.
		      or "qcom,ufs-phy-qmp-14nm" or "qcom,ufs-phy-qmp-v3"
		      or "qcom,ufs-phy-qrbtc-v2" according to the relevant phy in use.
- reg               : should contain PHY register address space (mandatory),
- reg-names         : indicates various resources passed to driver (via reg proptery) by name.
                      Required "reg-names" is "phy_mem".
@@ -27,6 +28,8 @@ Optional properties:
- vddp-ref-clk-supply   : phandle to UFS device ref_clk pad power supply
- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
- qcom,disable-lpm : disable various LPM mechanisms in UFS for platform compatibility
  (limit link to PWM Gear-1, 1-lane slow mode; disable hibernate, and avoid suspend/resume)

Example:

+119 −6
Original line number Diff line number Diff line
@@ -4,13 +4,15 @@ UFSHC nodes are defined to describe on-chip UFS host controllers.
Each UFS controller instance should have its own node.

Required properties:
- compatible		: must contain "jedec,ufs-1.1" or "jedec,ufs-2.0", may
			  also list one or more of the following:
- compatible		: must contain "jedec,ufs-1.1", may also list one or more
					  of the following:
					  "qcom,msm8994-ufshc"
					  "qcom,msm8996-ufshc"
					  "qcom,ufshc"
- interrupts        : <interrupt mapping for UFS host controller IRQ>
- reg               : <registers mapping>
		      first entry should contain UFS host controller register address space (mandatory),
                      second entry is the device ref. clock control register map (optional).

Optional properties:
- phys                  : phandle to UFS PHY node
@@ -38,9 +40,18 @@ Optional properties:
			  defined or a value in the array is "0" then it is assumed
			  that the frequency is set by the parent clock or a
			  fixed rate clock source.
- rpm-level		: UFS Runtime power management level. Following PM levels are suppported:
			  0 - Both UFS device and Link in active state (Highest power consumption)
			  1 - UFS device in active state but Link in Hibern8 state
			  2 - UFS device in Sleep state but Link in active state
			  3 - UFS device in Sleep state and Link in hibern8 state (default PM level)
			  4 - UFS device in Power-down state and Link in Hibern8 state
			  5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
- spm-level		: UFS System power management level. Allowed PM levels are same as rpm-level.
- ufs-qcom-crypto	: phandle to UFS-QCOM ICE (Inline Cryptographic Engine) node
- lanes-per-direction:	number of lanes available per direction - either 1 or 2.
			  Note that it is assume same number of lanes is used both
			  directions at once. If not specified, default is 2 lanes per direction.
			Note that it is assume same number of lanes is used both directions at once.
			If not specified, default is 2 lanes per direction.

Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
@@ -48,9 +59,10 @@ regulators or clocks are always on.
Example:
	ufshc@0xfc598000 {
		compatible = "jedec,ufs-1.1";
		reg = <0xfc598000 0x800>;
		reg = <0xfc598000 0x800>, <0xfd512074 0x4>;
		interrupts = <0 28 0>;

		ufs-qcom-crypto = <&ufs_ice>;
		vdd-hba-supply = <&xxx_reg0>;
		vdd-hba-fixed-regulator;
		vcc-supply = <&xxx_reg1>;
@@ -66,4 +78,105 @@ Example:
		freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
		phys = <&ufsphy1>;
		phy-names = "ufsphy";
		rpm-level = <3>;
		spm-level = <5>;
	};

==== MSM UFS platform driver properties =====
* For UFS host controller in MSM platform following clocks are required -
    Controller clock source -
        "core_clk_src", max-clock-frequency-hz = 200MHz

    Controller System clock branch:
        "core_clk" - Controller core clock

    AHB/AXI interface clocks:
        "iface_clk" - AHB interface clock
        "bus_clk" - AXI bus master clock

    PHY to controller symbol synchronization clocks:
        "rx_lane0_sync_clk" - RX Lane 0
        "rx_lane1_sync_clk" - RX Lane 1
        "tx_lane0_sync_clk" - TX Lane 0
        "tx_lane1_sync_clk" - TX Lane 1

    Optional reference clock input to UFS device
        "ref_clk", max-clock-frequency-hz = 19.2MHz

* Following bus parameters are required -
- qcom,msm-bus,name
- qcom,msm-bus,num-cases
- qcom,msm-bus,num-paths
- qcom,msm-bus,vectors-KBps
For the above four properties please refer to
Documentation/devicetree/bindings/arm/msm/msm_bus.txt
Note: The instantaneous bandwidth (IB) value in the vectors-KBps field should
      be zero as UFS data transfer path doesn't have latency requirements and
      voting for aggregated bandwidth (AB) should take care of providing
      optimum throughput requested.

- qcom,bus-vector-names: specifies string IDs for the corresponding
bus vectors in the same order as qcom,msm-bus,vectors-KBps property.

* The following parameters are optional, but required in order for PM QoS to be
enabled and functional in the driver:
- qcom,pm-qos-cpu-groups:		arrays of unsigned integers representing the cpu groups.
					The number of values in the array defines the number of cpu-groups.
					Each value is a bit-mask defining the cpus that take part in that cpu group.
					i.e. if bit N is set, then cpuN is a part of the cpu group. So basically,
					a cpu group corelated to a cpu cluster.
					A PM QoS request object is maintained for each cpu-group.
- qcom,pm-qos-cpu-group-latency-us:	array of values used for PM QoS voting, one for each cpu-group defined.
					the number of values must match the number of values defined in
					qcom,pm-qos-cpu-mask property.
- qcom,pm-qos-default-cpu:		PM QoS voting is based on the cpu associated with each IO request by the block layer.
					This defined the default cpu used for PM QoS voting in case a specific cpu value is not available.

Example:
	ufshc@0xfc598000 {
		...

		qcom,msm-bus,name = "ufs1";
		qcom,msm-bus,num-cases = <22>;
		qcom,msm-bus,num-paths = <2>;
		qcom,msm-bus,vectors-KBps =
				<95 512 0 0>, <1 650 0 0>,         /* No vote */

				<95 512 922 0>, <1 650 1000 0>,   /* PWM G1 */
				<95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */
				<95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */
				<95 512 7376 0>, <1 650 1000 0>,  /* PWM G4 */
				<95 512 1844 0>, <1 650 1000 0>, /* PWM G1 L2 */
				<95 512 3688 0>, <1 650 1000 0>, /* PWM G2 L2 */
				<95 512 7376 0>, <1 650 1000 0>,  /* PWM G3 L2 */
				<95 512 14752 0>, <1 650 1000 0>,  /* PWM G4 L2 */

				<95 512 127796 0>, <1 650 1000 0>,  /* HS G1 RA */
				<95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */
				<95 512 511181 0>, <1 650 1000 0>, /* HS G3 RA */
				<95 512 255591 0>, <1 650 1000 0>, /* HS G1 RA L2 */
				<95 512 511181 0>, <1 650 1000 0>, /* HS G2 RA L2 */
				<95 512 1022362 0>, <1 650 1000 0>, /* HS G3 RA L2 */

				<95 512 149422 0>, <1 650 1000 0>,  /* HS G1 RB */
				<95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */
				<95 512 596378 0>, <1 650 1000 0>, /* HS G3 RB */
				<95 512 298189 0>, <1 650 1000 0>, /* HS G1 RB L2 */
				<95 512 596378 0>, <1 650 1000 0>, /* HS G2 RB L2 */
				<95 512 1192756 0>, <1 650 1000 0>, /* HS G3 RB L2 */

				<95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */

		qcom,bus-vector-names = "MIN",
					"PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
					"PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2",
					"HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
					"HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2",
					"HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
					"HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2",
					"MAX";

		qcom,pm-qos-cpu-groups = <0x03 0x0C>; /* group0: cpu0, cpu1, group1: cpu2, cpu3 */
		qcom,pm-qos-cpu-group-latency-us = <200 300>; /* group0: 200us, group1: 300us */
		qcom,pm-qos-default-cpu = <0>;
	};
+2 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-v3.o
obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qrbtc-v2.o
obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
obj-$(CONFIG_PHY_BRCM_SATA)		+= phy-brcm-sata.o
obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
+30 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -91,6 +91,7 @@ struct ufs_qcom_phy {
	struct clk *ref_clk_src;
	struct clk *ref_clk_parent;
	struct clk *ref_clk;
	struct clk *ref_aux_clk;
	bool is_ref_clk_enabled;
	bool is_dev_ref_clk_enabled;
	struct ufs_qcom_phy_vreg vdda_pll;
@@ -107,6 +108,23 @@ struct ufs_qcom_phy {
	*/
	#define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE	BIT(0)

	/*
	 * On some UFS PHY HW revisions, UFS PHY power up calibration sequence
	 * cannot have SVS mode configuration otherwise calibration result
	 * cannot be used in HS-G3. So there are additional register writes must
	 * be done after the PHY is initialized but before the controller
	 * requests hibernate exit.
	 */
	#define UFS_QCOM_PHY_QUIRK_SVS_MODE	BIT(1)

	/*
	 * On some UFS PHY HW revisions, UFS PHY power up calibration sequence
	 * requires manual VCO tuning code and its better to rely on the VCO
	 * tuning code programmed by boot loader. Enable this quirk to enable
	 * programming the manually tuned VCO code.
	 */
	#define UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING	BIT(2)

	u8 host_ctrl_rev_major;
	u16 host_ctrl_rev_minor;
	u16 host_ctrl_rev_step;
@@ -116,6 +134,7 @@ struct ufs_qcom_phy {
	int cached_regs_table_size;
	bool is_powered_on;
	struct ufs_qcom_phy_specific_ops *phy_spec_ops;
	u32 vco_tune1_mode1;
};

/**
@@ -127,15 +146,21 @@ struct ufs_qcom_phy {
 * @is_physical_coding_sublayer_ready: pointer to a function that
 * checks pcs readiness. returns 0 for success and non-zero for error.
 * @set_tx_lane_enable: pointer to a function that enable tx lanes
 * @ctrl_rx_linecfg: pointer to a function that controls the Host Rx LineCfg
 * state.
 * @power_control: pointer to a function that controls analog rail of phy
 * and writes to QSERDES_RX_SIGDET_CNTRL attribute
 * @configure_lpm: pointer to a function that configures the phy
 * for low power mode.
 */
struct ufs_qcom_phy_specific_ops {
	int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
	void (*start_serdes)(struct ufs_qcom_phy *phy);
	int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
	void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
	void (*ctrl_rx_linecfg)(struct ufs_qcom_phy *phy, bool ctrl);
	void (*power_control)(struct ufs_qcom_phy *phy, bool val);
	int (*configure_lpm)(struct ufs_qcom_phy *phy, bool enable);
};

struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
@@ -156,4 +181,8 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
			struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
			struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
			bool is_rate_B);
void ufs_qcom_phy_write_tbl(struct ufs_qcom_phy *ufs_qcom_phy,
				struct ufs_qcom_phy_calibration *tbl,
				int tbl_size);

#endif
+130 −17
Original line number Diff line number Diff line
@@ -15,19 +15,49 @@
#include "phy-qcom-ufs-qmp-14nm.h"

#define UFS_PHY_NAME "ufs_phy_qmp_14nm"
#define UFS_PHY_VDDA_PHY_UV	(925000)

static
int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
					bool is_rate_B)
{
	int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
	int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
	int err;
	int tbl_size_A, tbl_size_B;
	struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
	u8 major = ufs_qcom_phy->host_ctrl_rev_major;
	u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
	u16 step = ufs_qcom_phy->host_ctrl_rev_step;

	tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
	tbl_B = phy_cal_table_rate_B;

	if ((major == 0x2) && (minor == 0x000) && (step == 0x0000)) {
		tbl_A = phy_cal_table_rate_A_2_0_0;
		tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_0_0);
	} else if ((major == 0x2) && (minor == 0x001) && (step == 0x0000)) {
		tbl_A = phy_cal_table_rate_A_2_1_0;
		tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_1_0);
	} else if ((major == 0x2) && (minor == 0x002) && (step == 0x0000)) {
		tbl_A = phy_cal_table_rate_A_2_2_0;
		tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_2_0);
		tbl_B = phy_cal_table_rate_B_2_2_0;
		tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B_2_2_0);
	} else {
		dev_err(ufs_qcom_phy->dev,
			"%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
			__func__, major, minor, step);
		err = -ENODEV;
		goto out;
	}

	err = ufs_qcom_phy_calibrate(ufs_qcom_phy, phy_cal_table_rate_A,
		tbl_size_A, phy_cal_table_rate_B, tbl_size_B, is_rate_B);
	err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
				     tbl_A, tbl_size_A,
				     tbl_B, tbl_size_B,
				     is_rate_B);

	if (ufs_qcom_phy->quirks & UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING)
		writel_relaxed(ufs_qcom_phy->vco_tune1_mode1,
			ufs_qcom_phy->mmio + QSERDES_COM_VCO_TUNE1_MODE1);
out:
	if (err)
		dev_err(ufs_qcom_phy->dev,
			"%s: ufs_qcom_phy_calibrate() failed %d\n",
@@ -38,8 +68,15 @@ int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
static
void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
{
	u8 major = phy_common->host_ctrl_rev_major;
	u16 minor = phy_common->host_ctrl_rev_minor;
	u16 step = phy_common->host_ctrl_rev_step;

	if ((major == 0x2) && (minor == 0x000) && (step == 0x0000))
		phy_common->quirks =
		UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
			UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE |
			UFS_QCOM_PHY_QUIRK_SVS_MODE |
			UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING;
}

static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
@@ -61,24 +98,66 @@ static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
			__func__, err);
		goto out;
	}
	phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
	phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;

	ufs_qcom_phy_qmp_14nm_advertise_quirks(phy_common);

	if (phy_common->quirks & UFS_QCOM_PHY_QUIRK_VCO_MANUAL_TUNING) {
		phy_common->vco_tune1_mode1 = readl_relaxed(phy_common->mmio +
						QSERDES_COM_VCO_TUNE1_MODE1);
		dev_info(phy_common->dev, "%s: vco_tune1_mode1 0x%x\n",
			__func__, phy_common->vco_tune1_mode1);
	}

out:
	return err;
}

static
void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val)
void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy,
					 bool power_ctrl)
{
	writel_relaxed(val ? 0x1 : 0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
	bool is_workaround_req = false;

	if (phy->quirks &
	    UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE)
		is_workaround_req = true;

	if (!power_ctrl) {
		/* apply PHY analog power collapse */
		if (is_workaround_req) {
			/* assert common reset before analog power collapse */
			writel_relaxed(0x1, phy->mmio + QSERDES_COM_SW_RESET);
			/*
			 * make sure that reset is propogated before analog
			 * power collapse
			 */
			mb();
		}
		/* apply analog power collapse */
		writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
		/*
		 * Make sure that PHY knows its analog rail is going to be
		 * powered OFF.
		 */
		mb();
	} else {
		/* bring PHY out of analog power collapse */
		writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
		/*
		 * Before any transactions involving PHY, ensure PHY knows
	 * that it's analog rail is powered ON (or OFF).
		 * that it's analog rail is powered ON.
		 */
		mb();
		if (is_workaround_req) {
			/*
			 * de-assert common reset after coming out of analog
			 * power collapse
			 */
			writel_relaxed(0x0, phy->mmio + QSERDES_COM_SW_RESET);
			/* make common reset is de-asserted before proceeding */
			mb();
		}
	}
}

static inline
@@ -90,6 +169,23 @@ void ufs_qcom_phy_qmp_14nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
	 */
}

static
void ufs_qcom_phy_qmp_14nm_ctrl_rx_linecfg(struct ufs_qcom_phy *phy, bool ctrl)
{
	u32 temp;

	temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);

	if (ctrl) /* enable RX LineCfg */
		temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
	else /* disable RX LineCfg */
		temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;

	writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
	/* make sure that RX LineCfg config applied before we return */
	mb();
}

static inline void ufs_qcom_phy_qmp_14nm_start_serdes(struct ufs_qcom_phy *phy)
{
	u32 tmp;
@@ -109,9 +205,24 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)

	err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
		val, (val & MASK_PCS_READY), 10, 1000000);
	if (err)
	if (err) {
		dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
			__func__, err);
		goto out;
	}

	if (phy_common->quirks & UFS_QCOM_PHY_QUIRK_SVS_MODE) {
		int i;

		for (i = 0; i < ARRAY_SIZE(phy_svs_mode_config_2_0_0); i++)
			writel_relaxed(phy_svs_mode_config_2_0_0[i].cfg_value,
				(phy_common->mmio +
				phy_svs_mode_config_2_0_0[i].reg_offset));
		/* apply above configuration immediately */
		mb();
	}

out:
	return err;
}

@@ -128,6 +239,7 @@ static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
	.start_serdes		= ufs_qcom_phy_qmp_14nm_start_serdes,
	.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
	.set_tx_lane_enable	= ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
	.ctrl_rx_linecfg	= ufs_qcom_phy_qmp_14nm_ctrl_rx_linecfg,
	.power_control		= ufs_qcom_phy_qmp_14nm_power_control,
};

@@ -140,6 +252,7 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)

	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
	if (!phy) {
		dev_err(dev, "%s: failed to allocate phy\n", __func__);
		err = -ENOMEM;
		goto out;
	}
Loading