Loading Documentation/devicetree/bindings/regulator/cpr-regulator.txt +24 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,25 @@ Optional properties: read in order to get the redundant quotient offset for a fuse corner. This property is the same as qcom,cpr-fuse-quot-offset except that it is only utilized if a chip is configured to use the redundant set of fuse values. - qcom,cpr-fuse-min-quot-diff: Array of values which define the minimum difference allowed between the adjusted quotients of the fuse corners. The length of the array should be equal to the value of the qcom,cpr-fuse-corners property. Where each element in the array maps to the fuse corners in increasing order. - qcom,cpr-min-quot-diff-adjustment: Array of integer tuples of target quotient offsets to be added to the adjusted target quotients of each fuse corner. When the quotient difference between two adjacent fuse corners is insufficient, the quotient for the higher fuse corner is replaced with that of the lower fuse corner plus the adjustment value. The elements in a tuple are ordered from lowest voltage corner to highest voltage corner. Each tuple must be of the length defined by qcom,cpr-fuse-corners. If the qcom,cpr-fuse-version-map property is specified, then qcom,cpr-min-quot-diff-adjustment must contain the same number of tuples as qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches for a given device, then the quotient adjustments defined in the second qcom,cpr-min-quot-diff-adjustment tuple will be applied. If the qcom,cpr-fuse-version-map property is not specified, then qcom,cpr-min-quot-diff-adjustment must contain a single tuple which is then applied unconditionally. The qcom,cpr-min-quot-diff-adjustment property must be specified if the qcom,cpr-fuse-min-quot-diff property is specified. Example: apc_vreg_corner: regulator@f9018000 { Loading Loading @@ -720,6 +739,11 @@ Example: <0 0 (-100000)>, <0 0 (-100000)>, <0 0 (-45000)>; qcom,cpr-fuse-min-quot-diff = <0 0 40>; qcom,cpr-min-quot-diff-adjustment = <0 0 0>, <0 0 72>, <0 0 104>; qcom,cpr-virtual-corner-init-voltage-adjustment = <0 0 0 (-10000) 0 0 0 0 0 0 0 0>, <0 0 0 0 0 0 0 0 0 0 0 (-20000)>, Loading drivers/regulator/cpr-regulator.c +100 −4 Original line number Diff line number Diff line /* * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2015, The 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 Loading Loading @@ -2721,6 +2721,87 @@ done: return rc; } static int cpr_minimum_quot_difference_adjustment(struct platform_device *pdev, struct cpr_regulator *cpr_vreg) { struct device_node *of_node = pdev->dev.of_node; int tuple_count, tuple_match; int rc, i, len = 0; u32 index, adjust_quot = 0; u32 *min_diff_quot; if (!of_find_property(of_node, "qcom,cpr-fuse-min-quot-diff", NULL)) /* No conditional adjustment needed on revised quotients. */ return 0; if (!of_find_property(of_node, "qcom,cpr-min-quot-diff-adjustment", &len)) { cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment not specified\n"); return -ENODEV; } if (cpr_vreg->cpr_fuse_map_count) { if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) /* No matching index to use for quotient adjustment. */ return 0; tuple_count = cpr_vreg->cpr_fuse_map_count; tuple_match = cpr_vreg->cpr_fuse_map_match; } else { tuple_count = 1; tuple_match = 0; } if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) { cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment length=%d is invalid\n", len); return -EINVAL; } min_diff_quot = kzalloc(cpr_vreg->num_fuse_corners * sizeof(u32), GFP_KERNEL); if (!min_diff_quot) { cpr_err(cpr_vreg, "memory alloc failed\n"); return -ENOMEM; } rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-min-quot-diff", min_diff_quot, cpr_vreg->num_fuse_corners); if (rc < 0) { cpr_err(cpr_vreg, "qcom,cpr-fuse-min-quot-diff reading failed, rc = %d\n", rc); goto error; } for (i = CPR_FUSE_CORNER_MIN + 1; i <= cpr_vreg->num_fuse_corners; i++) { if ((cpr_vreg->cpr_fuse_target_quot[i] - cpr_vreg->cpr_fuse_target_quot[i - 1]) <= (int)min_diff_quot[i - CPR_FUSE_CORNER_MIN]) { index = tuple_match * cpr_vreg->num_fuse_corners + i - CPR_FUSE_CORNER_MIN; rc = of_property_read_u32_index(of_node, "qcom,cpr-min-quot-diff-adjustment", index, &adjust_quot); if (rc) { cpr_err(cpr_vreg, "could not read qcom,cpr-min-quot-diff-adjustment index %u, rc=%d\n", index, rc); goto error; } cpr_vreg->cpr_fuse_target_quot[i] = cpr_vreg->cpr_fuse_target_quot[i - 1] + adjust_quot; cpr_info(cpr_vreg, "Corner[%d]: revised adjusted quotient = %d\n", i, cpr_vreg->cpr_fuse_target_quot[i]); }; } error: kfree(min_diff_quot); return rc; } static int cpr_adjust_target_quots(struct platform_device *pdev, struct cpr_regulator *cpr_vreg) { Loading Loading @@ -2772,6 +2853,11 @@ static int cpr_adjust_target_quots(struct platform_device *pdev, } } rc = cpr_minimum_quot_difference_adjustment(pdev, cpr_vreg); if (rc) cpr_err(cpr_vreg, "failed to apply minimum quot difference rc=%d\n", rc); return rc; } Loading Loading @@ -2814,10 +2900,10 @@ static int cpr_check_allowed(struct platform_device *pdev, return rc; } if (!allow_status) cpr_vreg->cpr_fuse_disable = true; else if (allow_status && !cpr_vreg->cpr_fuse_disable) cpr_vreg->cpr_fuse_disable = false; else cpr_vreg->cpr_fuse_disable = true; cpr_info(cpr_vreg, "CPR closed loop is %s for fuse revision %d\n", cpr_vreg->cpr_fuse_disable ? "disabled" : "enabled", Loading Loading @@ -3030,6 +3116,16 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev, cpr_vreg->cpr_fuse_target_quot[i]); } for (i = CPR_FUSE_CORNER_MIN + 1; i <= cpr_vreg->num_fuse_corners; i++) { if (cpr_vreg->cpr_fuse_target_quot[i] < cpr_vreg->cpr_fuse_target_quot[i - 1]) { cpr_vreg->cpr_fuse_disable = true; cpr_err(cpr_vreg, "invalid quotient values; permanently disabling CPR\n"); goto error; } } rc = cpr_adjust_target_quots(pdev, cpr_vreg); if (rc) goto error; Loading Loading
Documentation/devicetree/bindings/regulator/cpr-regulator.txt +24 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,25 @@ Optional properties: read in order to get the redundant quotient offset for a fuse corner. This property is the same as qcom,cpr-fuse-quot-offset except that it is only utilized if a chip is configured to use the redundant set of fuse values. - qcom,cpr-fuse-min-quot-diff: Array of values which define the minimum difference allowed between the adjusted quotients of the fuse corners. The length of the array should be equal to the value of the qcom,cpr-fuse-corners property. Where each element in the array maps to the fuse corners in increasing order. - qcom,cpr-min-quot-diff-adjustment: Array of integer tuples of target quotient offsets to be added to the adjusted target quotients of each fuse corner. When the quotient difference between two adjacent fuse corners is insufficient, the quotient for the higher fuse corner is replaced with that of the lower fuse corner plus the adjustment value. The elements in a tuple are ordered from lowest voltage corner to highest voltage corner. Each tuple must be of the length defined by qcom,cpr-fuse-corners. If the qcom,cpr-fuse-version-map property is specified, then qcom,cpr-min-quot-diff-adjustment must contain the same number of tuples as qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches for a given device, then the quotient adjustments defined in the second qcom,cpr-min-quot-diff-adjustment tuple will be applied. If the qcom,cpr-fuse-version-map property is not specified, then qcom,cpr-min-quot-diff-adjustment must contain a single tuple which is then applied unconditionally. The qcom,cpr-min-quot-diff-adjustment property must be specified if the qcom,cpr-fuse-min-quot-diff property is specified. Example: apc_vreg_corner: regulator@f9018000 { Loading Loading @@ -720,6 +739,11 @@ Example: <0 0 (-100000)>, <0 0 (-100000)>, <0 0 (-45000)>; qcom,cpr-fuse-min-quot-diff = <0 0 40>; qcom,cpr-min-quot-diff-adjustment = <0 0 0>, <0 0 72>, <0 0 104>; qcom,cpr-virtual-corner-init-voltage-adjustment = <0 0 0 (-10000) 0 0 0 0 0 0 0 0>, <0 0 0 0 0 0 0 0 0 0 0 (-20000)>, Loading
drivers/regulator/cpr-regulator.c +100 −4 Original line number Diff line number Diff line /* * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2015, The 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 Loading Loading @@ -2721,6 +2721,87 @@ done: return rc; } static int cpr_minimum_quot_difference_adjustment(struct platform_device *pdev, struct cpr_regulator *cpr_vreg) { struct device_node *of_node = pdev->dev.of_node; int tuple_count, tuple_match; int rc, i, len = 0; u32 index, adjust_quot = 0; u32 *min_diff_quot; if (!of_find_property(of_node, "qcom,cpr-fuse-min-quot-diff", NULL)) /* No conditional adjustment needed on revised quotients. */ return 0; if (!of_find_property(of_node, "qcom,cpr-min-quot-diff-adjustment", &len)) { cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment not specified\n"); return -ENODEV; } if (cpr_vreg->cpr_fuse_map_count) { if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) /* No matching index to use for quotient adjustment. */ return 0; tuple_count = cpr_vreg->cpr_fuse_map_count; tuple_match = cpr_vreg->cpr_fuse_map_match; } else { tuple_count = 1; tuple_match = 0; } if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) { cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment length=%d is invalid\n", len); return -EINVAL; } min_diff_quot = kzalloc(cpr_vreg->num_fuse_corners * sizeof(u32), GFP_KERNEL); if (!min_diff_quot) { cpr_err(cpr_vreg, "memory alloc failed\n"); return -ENOMEM; } rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-min-quot-diff", min_diff_quot, cpr_vreg->num_fuse_corners); if (rc < 0) { cpr_err(cpr_vreg, "qcom,cpr-fuse-min-quot-diff reading failed, rc = %d\n", rc); goto error; } for (i = CPR_FUSE_CORNER_MIN + 1; i <= cpr_vreg->num_fuse_corners; i++) { if ((cpr_vreg->cpr_fuse_target_quot[i] - cpr_vreg->cpr_fuse_target_quot[i - 1]) <= (int)min_diff_quot[i - CPR_FUSE_CORNER_MIN]) { index = tuple_match * cpr_vreg->num_fuse_corners + i - CPR_FUSE_CORNER_MIN; rc = of_property_read_u32_index(of_node, "qcom,cpr-min-quot-diff-adjustment", index, &adjust_quot); if (rc) { cpr_err(cpr_vreg, "could not read qcom,cpr-min-quot-diff-adjustment index %u, rc=%d\n", index, rc); goto error; } cpr_vreg->cpr_fuse_target_quot[i] = cpr_vreg->cpr_fuse_target_quot[i - 1] + adjust_quot; cpr_info(cpr_vreg, "Corner[%d]: revised adjusted quotient = %d\n", i, cpr_vreg->cpr_fuse_target_quot[i]); }; } error: kfree(min_diff_quot); return rc; } static int cpr_adjust_target_quots(struct platform_device *pdev, struct cpr_regulator *cpr_vreg) { Loading Loading @@ -2772,6 +2853,11 @@ static int cpr_adjust_target_quots(struct platform_device *pdev, } } rc = cpr_minimum_quot_difference_adjustment(pdev, cpr_vreg); if (rc) cpr_err(cpr_vreg, "failed to apply minimum quot difference rc=%d\n", rc); return rc; } Loading Loading @@ -2814,10 +2900,10 @@ static int cpr_check_allowed(struct platform_device *pdev, return rc; } if (!allow_status) cpr_vreg->cpr_fuse_disable = true; else if (allow_status && !cpr_vreg->cpr_fuse_disable) cpr_vreg->cpr_fuse_disable = false; else cpr_vreg->cpr_fuse_disable = true; cpr_info(cpr_vreg, "CPR closed loop is %s for fuse revision %d\n", cpr_vreg->cpr_fuse_disable ? "disabled" : "enabled", Loading Loading @@ -3030,6 +3116,16 @@ static int cpr_init_cpr_efuse(struct platform_device *pdev, cpr_vreg->cpr_fuse_target_quot[i]); } for (i = CPR_FUSE_CORNER_MIN + 1; i <= cpr_vreg->num_fuse_corners; i++) { if (cpr_vreg->cpr_fuse_target_quot[i] < cpr_vreg->cpr_fuse_target_quot[i - 1]) { cpr_vreg->cpr_fuse_disable = true; cpr_err(cpr_vreg, "invalid quotient values; permanently disabling CPR\n"); goto error; } } rc = cpr_adjust_target_quots(pdev, cpr_vreg); if (rc) goto error; Loading