On Thu, 2014-11-06 at 08:55 -0800, Bjorn Andersson wrote: > On Wed, Nov 5, 2014 at 11:54 PM, Ivan T. Ivanov <iivanov@xxxxxxxxxx> wrote: > > On Wed, 2014-11-05 at 17:36 -0800, Bjorn Andersson wrote: > > > On Wed, Nov 5, 2014 at 10:31 AM, Ivan T. Ivanov <iivanov@xxxxxxxxxx> wrote: > [..] > > > > Some of the child device drivers have to know PMIC chip revision. > > > > > > > > > > So your plan is to have a strstr(parent->compatible, "-v2") there? > > > > Actually also PMIC subtype (pm8841, pm8226...) is also required, so > > the plan is to have something like this: > > > > { > > static const struct of_device_id pmic_match_table[] = { > > { .compatible = "qcom,pm8941-v1.0" }, > > { .compatible = "qcom,pm8841-v0.0" }, > > { } > > > > }; > > > > const struct of_device_id *match; > > > > match = of_match_device(pmic_match_table, pdev->dev.parent); > > if (match) { > > dev_info(&pdev->dev, "%s chip detected\n", match->compatible); > > } > > } > > > > To me this is a hack, you should not alter the devicetree to make it > "better express the hardware". Either you know these things from boot > and they go in device tree, or you can probe them and they should not > go in device tree. > > If you really need these values you should expose them through some api. I would like to avoid compile time dependency between these drivers. There are several precedents of using of_update_property() for enhancing compatible property already. > > > > Could you be a little bit more elaborate on what you're trying to do > > > and which child devices that might be? > > > > For example ADC drivers are required temperature compensation based > > on PMIC variant and chip manufacturer. > > > > I see, is that compensation of any practical value? Or is the > compensation of academic proportions? It depends of what you mean by academic :-). Attached file have test application which dump difference between non compensated and compensated values for different temperature, manufacture and input value. Output format of the program is: Column 1: manufacturer GF=0, SMIC=1, TSMC=2 Column 2: chip revision Column 3: die temperature in mili deg Celsius Column 4: input for compensation in micro Volts Column 5: compensated result in micro Volts Column 6: difference in micro Volts Regards, Ivan
#include <stdio.h> /* SW index's for PMIC type and version used by QPNP VADC and IADC */ #define REV_ID_8941_3_1 1 #define REV_ID_8026_1_0 2 #define REV_ID_8026_2_0 3 #define REV_ID_8110_1_0 4 #define REV_ID_8026_2_1 5 #define REV_ID_8110_2_0 6 #define REV_ID_8026_2_2 7 #define REV_ID_8941_3_0 8 #define REV_ID_8941_2_0 9 #define REV_ID_8916_1_0 10 #define REV_ID_8916_1_1 11 #define REV_ID_8916_2_0 12 #define FACTORY_GF 0 #define FACTORY_SMIC 1 #define FACTORY_TSMC 2 #define VBAT_COEFF_1 3000 #define VBAT_COEFF_2 45810000 #define VBAT_COEFF_3 100000 #define VBAT_COEFF_4 3500 #define VBAT_COEFF_5 80000000 #define VBAT_COEFF_6 4400 #define VBAT_COEFF_7 32200000 #define VBAT_COEFF_8 3880 #define VBAT_COEFF_9 5770 #define VBAT_COEFF_10 3660 #define VBAT_COEFF_11 5320 #define VBAT_COEFF_12 8060000 #define VBAT_COEFF_13 102640000 #define VBAT_COEFF_14 22220000 #define VBAT_COEFF_15 83060000 #define VBAT_COEFF_16 2810 #define VBAT_COEFF_17 5260 #define VBAT_COEFF_18 8027 #define VBAT_COEFF_19 2347 #define VBAT_COEFF_20 6043 #define VBAT_COEFF_21 1914 #define VBAT_OFFSET_SMIC 9446 #define VBAT_OFFSET_GF 9441 #define OCV_OFFSET_SMIC 4596 #define OCV_OFFSET_GF 5896 #define VBAT_COEFF_22 6800 #define VBAT_COEFF_23 3500 #define VBAT_COEFF_24 4360 #define VBAT_COEFF_25 8060 #define VBAT_COEFF_26 7895 #define VBAT_COEFF_27 5658 #define VBAT_COEFF_28 5760 #define VBAT_COEFF_29 7900 #define VBAT_COEFF_30 5660 #define VBAT_COEFF_31 3620 #define VBAT_COEFF_32 1230 #define VBAT_COEFF_33 5760 #define VBAT_COEFF_34 4080 #define VBAT_COEFF_35 7000 #define VBAT_COEFF_36 3040 #define VBAT_COEFF_37 3850 #define VBAT_COEFF_38 5000 #define VBAT_COEFF_39 2610 #define VBAT_COEFF_40 4190 #define VBAT_COEFF_41 5800 #define VBAT_COEFF_42 2620 #define VBAT_COEFF_43 4030 #define VBAT_COEFF_44 3230 #define VBAT_COEFF_45 3450 #define VBAT_COEFF_46 2120 #define VBAT_COEFF_47 3560 #define VBAT_COEFF_48 2190 static long qpnp_ocv_comp(int version, int factory, long result, long die_temp) { long temp_var = 0, offset = 0; if (version == REV_ID_8026_2_2) { if (die_temp > 25000) return result; } switch (version) { case REV_ID_8941_3_1: switch (factory) { case FACTORY_TSMC: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_4)); break; default: case FACTORY_GF: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_1)); break; } break; case REV_ID_8026_1_0: switch (factory) { case FACTORY_TSMC: temp_var = (((die_temp * (-VBAT_COEFF_10)) - VBAT_COEFF_14)); break; default: case FACTORY_GF: temp_var = (((die_temp * (-VBAT_COEFF_8)) + VBAT_COEFF_12)); break; } break; case REV_ID_8026_2_0: case REV_ID_8026_2_1: switch (factory) { case FACTORY_TSMC: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_10)); break; default: case FACTORY_GF: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_8)); break; } break; case REV_ID_8026_2_2: switch (factory) { case FACTORY_TSMC: result -= VBAT_COEFF_22; temp_var = (die_temp - 25000) * VBAT_COEFF_24; break; default: case FACTORY_GF: result -= VBAT_COEFF_22; temp_var = (die_temp - 25000) * VBAT_COEFF_25; break; } break; case REV_ID_8110_2_0: switch (factory) { case FACTORY_SMIC: result -= OCV_OFFSET_SMIC; if (die_temp < 25000) temp_var = VBAT_COEFF_18; else temp_var = VBAT_COEFF_19; temp_var = (die_temp - 25000) * temp_var; break; default: case FACTORY_GF: result -= OCV_OFFSET_GF; if (die_temp < 25000) temp_var = VBAT_COEFF_20; else temp_var = VBAT_COEFF_21; temp_var = (die_temp - 25000) * temp_var; break; } break; case REV_ID_8916_1_0: switch (factory) { case FACTORY_SMIC: if (die_temp < 25000) temp_var = VBAT_COEFF_26; else temp_var = VBAT_COEFF_27; temp_var = (die_temp - 25000) * temp_var; break; default: case FACTORY_GF: offset = OCV_OFFSET_GF; if (die_temp < 25000) temp_var = VBAT_COEFF_26; else temp_var = VBAT_COEFF_27; temp_var = (die_temp - 25000) * temp_var; break; } break; case REV_ID_8916_1_1: switch (factory) { /* FAB_ID is zero */ case FACTORY_GF: if (die_temp < 25000) temp_var = VBAT_COEFF_29; else temp_var = VBAT_COEFF_30; temp_var = (die_temp - 25000) * temp_var; break; /* FAB_ID is non-zero */ default: if (die_temp < 25000) temp_var = VBAT_COEFF_31; else temp_var = (-VBAT_COEFF_32); temp_var = (die_temp - 25000) * temp_var; break; } break; case REV_ID_8916_2_0: switch (factory) { case FACTORY_SMIC: offset = (-VBAT_COEFF_38); if (die_temp < 0) temp_var = die_temp * VBAT_COEFF_36; else if (die_temp > 40000) temp_var = ((die_temp - 40000) * (-VBAT_COEFF_37)); break; case FACTORY_TSMC: if (die_temp < 10000) temp_var = ((die_temp - 10000) * VBAT_COEFF_41); else if (die_temp > 50000) temp_var = ((die_temp - 50000) * (-VBAT_COEFF_42)); break; default: case FACTORY_GF: if (die_temp < 20000) temp_var = ((die_temp - 20000) * VBAT_COEFF_45); else if (die_temp > 40000) temp_var = ((die_temp - 40000) * (-VBAT_COEFF_46)); break; } break; default: temp_var = 0; break; } temp_var = temp_var / VBAT_COEFF_3; temp_var = 1000000 + temp_var; result = result * temp_var; if (offset) result -= offset; result = result / 1000000; return result; } static long qpnp_vbat_sns_comp(int version, int factory, long result, long die_temp) { long temp_var = 0, offset = 0; if (version != REV_ID_8941_3_1) { /* min(die_temp_c, 60_degC) */ if (die_temp > 60000) die_temp = 60000; } switch (version) { case REV_ID_8941_3_1: switch (factory) { case FACTORY_TSMC: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_1)); break; default: case FACTORY_GF: /* min(die_temp_c, 60_degC) */ if (die_temp > 60000) die_temp = 60000; temp_var = ((die_temp - 25000) * (-VBAT_COEFF_1)); break; } break; case REV_ID_8026_1_0: switch (factory) { case FACTORY_TSMC: temp_var = (((die_temp * (-VBAT_COEFF_11)) + VBAT_COEFF_15)); break; default: case FACTORY_GF: temp_var = (((die_temp * (-VBAT_COEFF_9)) + VBAT_COEFF_13)); break; } break; case REV_ID_8026_2_0: case REV_ID_8026_2_1: switch (factory) { case FACTORY_TSMC: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_11)); break; default: case FACTORY_GF: temp_var = ((die_temp - 25000) * (-VBAT_COEFF_9)); break; } break; case REV_ID_8026_2_2: switch (factory) { case FACTORY_TSMC: result -= VBAT_COEFF_23; temp_var = 0; break; default: case FACTORY_GF: result -= VBAT_COEFF_23; temp_var = 0; break; } break; case REV_ID_8110_2_0: switch (factory) { case FACTORY_SMIC: result -= VBAT_OFFSET_SMIC; temp_var = ((die_temp - 25000) * (VBAT_COEFF_17)); break; default: case FACTORY_GF: result -= VBAT_OFFSET_GF; temp_var = ((die_temp - 25000) * (VBAT_COEFF_16)); break; } break; case REV_ID_8916_1_0: switch (factory) { case FACTORY_SMIC: temp_var = ((die_temp - 25000) * (VBAT_COEFF_28)); break; default: case FACTORY_GF: temp_var = ((die_temp - 25000) * (VBAT_COEFF_28)); break; } break; case REV_ID_8916_1_1: switch (factory) { /* FAB_ID is zero */ case FACTORY_GF: temp_var = ((die_temp - 25000) * (VBAT_COEFF_33)); break; /* FAB_ID is non-zero */ default: offset = VBAT_COEFF_35; if (die_temp > 50000) { temp_var = ((die_temp - 25000) * (VBAT_COEFF_34)); } break; } break; case REV_ID_8916_2_0: switch (factory) { case FACTORY_SMIC: if (die_temp < 0) { temp_var = (die_temp * VBAT_COEFF_39); } else if (die_temp > 40000) { temp_var = ((die_temp - 40000) * (-VBAT_COEFF_40)); } break; case FACTORY_TSMC: if (die_temp < 10000) temp_var = ((die_temp - 10000) * VBAT_COEFF_43); else if (die_temp > 50000) temp_var = ((die_temp - 50000) * (-VBAT_COEFF_44)); break; default: case FACTORY_GF: if (die_temp < 20000) temp_var = ((die_temp - 20000) * VBAT_COEFF_47); else if (die_temp > 40000) temp_var = ((die_temp - 40000) * (-VBAT_COEFF_48)); break; } break; default: temp_var = 0; break; } temp_var = temp_var / VBAT_COEFF_3; temp_var = 1000000 + temp_var; result = result * temp_var; if (offset) result -= offset; result = result / 1000000; return result; } int main(void) { long result, original, die_temp, diff; int version, factory; printf("==================================================================\n"); printf(" OCV Compensation \n"); printf("==================================================================\n"); for (factory = FACTORY_GF; factory <= FACTORY_TSMC; factory++) { for (version = REV_ID_8941_3_1; version <= REV_ID_8916_2_0; version++) { for (die_temp = 0; die_temp <= 100000; die_temp += 10000) { for (original = 0; original <= 1800000; original += 100000) { result = qpnp_ocv_comp(version, factory, original, die_temp); diff = result - original; printf("%d\t%d\t%ld\t%ld\t%ld\t%ld\n", factory, version, die_temp, original, result, diff); } } } } printf("==================================================================\n"); printf(" VBAT Compensation \n"); printf("==================================================================\n"); for (factory = FACTORY_GF; factory <= FACTORY_TSMC; factory++) { for (version = REV_ID_8941_3_1; version <= REV_ID_8916_2_0; version++) { for (die_temp = 0; die_temp <= 100000; die_temp += 10000) { for (original = 0; original <= 1800000; original += 100000) { result = qpnp_vbat_sns_comp(version, factory, original, die_temp); diff = result - original; printf("%d\t%d\t%ld\t%ld\t%ld\t%ld\n", factory, version, die_temp, original, result, diff); } } } } return 0; }