summaryrefslogtreecommitdiff
path: root/drivers/misc/sprd_otp/otp-helper.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/misc/sprd_otp/otp-helper.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/misc/sprd_otp/otp-helper.c')
-rw-r--r--drivers/misc/sprd_otp/otp-helper.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/drivers/misc/sprd_otp/otp-helper.c b/drivers/misc/sprd_otp/otp-helper.c
new file mode 100644
index 00000000..743dc6e0
--- /dev/null
+++ b/drivers/misc/sprd_otp/otp-helper.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/err.h>
+#include "sprd_otp.h"
+
+#define BLK_UID_HIGH ( 0 )
+#define BLK_UID_LOW ( 1 )
+#define BLK_ADC_DETA ( 7 )
+#define BLK_CCCV_DETA ( 9 )
+
+#define BLK_FGU_DETA_ABC ( 8 )
+#define BLK_FGU_DETA_D ( 9 )
+
+#define BLK_WIDTH_OTP_EMEMORY ( 8 ) /* bit counts */
+#define BLK_ADC_DETA_ABC_OTP ( 7 ) /* start block for ADC otp delta */
+
+u32 __weak __ddie_efuse_read(int blk_index)
+{
+ return 0;
+}
+/*---------------------------------------------------------------------------*
+ * Efuse public API functions for other kernel modules *
+ *---------------------------------------------------------------------------*/
+u64 sci_efuse_get_uid(void)
+{
+ u64 uid_hi, uid_lo;
+
+ uid_hi = __ddie_efuse_read(BLK_UID_HIGH);
+ uid_lo = __ddie_efuse_read(BLK_UID_LOW);
+
+ /* fill system serial number */
+ return ((uid_hi << 32ull) | uid_lo);
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_get_uid);
+
+#if defined(CONFIG_ARCH_SCX20L) || defined(CONFIG_ARCH_SCX35L64)\
+|| defined(CONFIG_ARCH_SCX20)
+#define BLK_THM_DETA (13)
+#define THM_CAL_BIT (26)
+#else
+#define BLK_THM_DETA (7)
+#define THM_CAL_BIT (24)
+#endif
+int sci_efuse_thermal_cal_get(int *cal)
+{
+ u32 data=__ddie_efuse_read(BLK_THM_DETA);
+ int thm_cal = (data >> THM_CAL_BIT) & 0x001F;
+ if (thm_cal ==0) {
+ *cal = 0;
+ return -1;
+ }
+ *cal = thm_cal -16;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sci_efuse_thermal_cal_get);
+
+#define BASE_ADC_P0 711 //3.6V
+#define BASE_ADC_P1 830 //4.2V
+#define VOL_P0 3600
+#define VOL_P1 4200
+#define ADC_DATA_OFFSET 128
+int sci_efuse_calibration_get(unsigned int *p_cal_data)
+{
+ unsigned int deta = 0;
+ unsigned short adc_temp = 0;
+
+#if defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
+ /* verify the otp data of ememory written or not */
+ adc_temp = (__adie_efuse_read(0) & BIT(7));
+ if (adc_temp)
+ return 0;
+
+ deta = __adie_efuse_read_bits(BLK_ADC_DETA_ABC_OTP * BLK_WIDTH_OTP_EMEMORY, 16);
+#elif defined(CONFIG_ARCH_SCX30G) || defined(CONFIG_ARCH_SCX35L)
+ deta = __ddie_efuse_read(BLK_ADC_DETA);
+ WARN_ON(!(deta & BIT(31))); /* BIT 31 is protected bit */
+#else
+ #warning "AuxADC CAL DETA need fixing"
+#endif
+
+ pr_info("%s() get efuse block %u, deta: 0x%08x\n", __func__, BLK_ADC_DETA, deta);
+
+ deta &= 0xFFFFFF; /* get BIT0 ~ BIT23) in block 7 */
+
+ if ((!deta) || (p_cal_data == NULL)) {
+ return 0;
+ }
+ //adc 3.6V
+ adc_temp = ((deta >> 8) & 0x00FF) + BASE_ADC_P0 - ADC_DATA_OFFSET;
+ p_cal_data[1] = (VOL_P0) | ((adc_temp << 2) << 16);
+
+ //adc 4.2V
+ adc_temp = (deta & 0x00FF) + BASE_ADC_P1 - ADC_DATA_OFFSET;
+ p_cal_data[0] = (VOL_P1) | ((adc_temp << 2) << 16);
+
+ return 1;
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_calibration_get);
+
+int sci_efuse_cccv_cal_get(unsigned int *p_cal_data)
+{
+#if defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
+ unsigned int data,blk0;
+
+ blk0 = __adie_efuse_read(0);
+
+ if (blk0 & (1 << 7)) {
+ return 0;
+ }
+
+ data = __adie_efuse_read_bits(BITSINDEX(14, 0), 6);
+ pr_info("sci_efuse_cccv_cal_get data:0x%x\n", data);
+ *p_cal_data = (data) & 0x003F;
+#else
+ unsigned int data;
+
+ data = __ddie_efuse_read(BLK_CCCV_DETA);
+ data &= ~(1 << 31);
+
+ pr_info("sci_efuse_cccv_cal_get data:0x%x\n", data);
+
+ if ((!data) || (p_cal_data == NULL)) {
+ return 0;
+ }
+
+ *p_cal_data = (data >> 24) & 0x003F; /*block 9, bit 29..24 */
+#endif
+ return 1;
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_cccv_cal_get);
+
+int sci_efuse_fgu_cal_get(unsigned int *p_cal_data)
+{
+#if defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
+ unsigned int data,blk0;
+
+ blk0 = __adie_efuse_read(0);
+
+ if (blk0 & (1 << 7)) {
+ return 0;
+ }
+
+ data = __adie_efuse_read_bits(BITSINDEX(12, 0), 9);
+ printk("sci_efuse_fgu_cal_get 4.2 data data:0x%x\n", data);
+ p_cal_data[0] = (data + 6963) - 4096 - 256; //4.0V or 4.2V
+
+ data = __adie_efuse_read_bits(BITSINDEX(14, 2), 6);
+ printk("sci_efuse_fgu_cal_get 3.6 data data:0x%x\n", data);
+ p_cal_data[1] = p_cal_data[0] - 410 - data + 16; //3.6V
+
+ data = __adie_efuse_read_bits(BITSINDEX(13, 1), 9);
+ printk("sci_efuse_fgu_cal_get 0 data data:0x%x\n", data);
+ p_cal_data[2] = (((data) & 0x1FF) + 8192) - 256;
+
+ return 1;
+#else
+ unsigned int data;
+
+ data = __ddie_efuse_read(BLK_FGU_DETA_ABC);
+ data &= ~(1 << 31);
+
+ pr_info("sci_efuse_fgu_cal_get ABC data:0x%x\n", data);
+
+ if ((!data) || (p_cal_data == NULL)) {
+ return 0;
+ }
+
+ p_cal_data[0] = (((data >> 16) & 0x1FF) + 6963) - 4096 - 256; //4.0V or 4.2V
+ p_cal_data[1] = p_cal_data[0] - 410 - ((data >> 25) & 0x3F) + 16; //3.6V
+ p_cal_data[2] = (((data) & 0x1FF) + 8192) - 256;
+
+ return 1;
+#endif
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_fgu_cal_get);
+
+/*
+ * sci_efuse_get_apt_cal - read apt data saved in efuse
+ * @pdata: apt data pointer for dcdcwpa (unit: uV)
+ * pdata[0] -> 3v
+ * pdata[1] -> 0.8v
+ * @num: the length of apt data
+ *
+ * retruns 0 if success, else
+ * returns negative number.
+ */
+#define APT_CAL_DATA_BLK ( 10 )
+#define OFFSET2VOL(p, uv) ( ((p) - 128) * (uv) / 256)
+int sci_efuse_get_apt_cal(unsigned int *pdata, int num)
+{
+ int i = 0;
+ u32 efuse_data = 0;
+ u8 *offset = (u8 *) & efuse_data;
+ const unsigned int vol_ref[2] = {
+ 3000000, //3v
+ 800000, //0.8v
+ };
+
+ /* Fixme: dcdcwpa only support two points(3.6v / 0.8v) voltage calibration */
+ BUG_ON(num > 2);
+
+ efuse_data = __ddie_efuse_read(APT_CAL_DATA_BLK);
+
+ pr_info("%s efuse data: 0x%08x\n", __func__, efuse_data);
+
+ WARN_ON(!(efuse_data & BIT(31))); /* BIT 31 is protected bit */
+ efuse_data &= 0xFFFF; /* get BIT0 ~ BIT15 in block 10 */
+
+ if (!(efuse_data) || (!pdata)) {
+ return -1;
+ }
+
+ printk("%s: ", __func__);
+ for (i = 0; i < num; i++) {
+ pdata[i] = (unsigned int)OFFSET2VOL(offset[i], vol_ref[i]);
+ printk("(%duV : %08d), ", vol_ref[i], pdata[i]);
+ }
+ printk("\n");
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_get_apt_cal);
+
+/*
+ * sci_efuse_get_cal - read 4 point adc calibration data saved in efuse
+ * @pdata: adc data pointer
+ * pdata[0] -> 4.2v
+ * pdata[1] -> 3.6v
+ * pdata[2] -> 0.4v
+ * @num: the length of adc data
+ *
+ * retruns 0 if success, else
+ * returns negative number.
+ */
+#define BLK_ADC_DETA_ABC ( 7 )
+#define BLK_ADC_DETA_D ( 9 )
+#define DELTA2ADC(_delta_, _Ideal_) ( ((_delta_) + (_Ideal_) - 128) << 2 )
+#define ADC_VOL(_delta_, _Ideal_, vol) ( (DELTA2ADC(_delta_, _Ideal_) << 16) | (vol) )
+
+int sci_efuse_get_cal(unsigned int *pdata, int num)
+{
+ int i;
+ u32 efuse_data = 0;
+ u8 *delta = (u8 *) & efuse_data;
+ const u16 ideal[3][2] = {
+ {4200, 830}, /* FIXME: efuse only support 10bits */
+ {3600, 711},
+ {400, 79},
+ };
+
+#if defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
+ /* verify the otp data of ememory written or not */
+ efuse_data = (__adie_efuse_read(0) & BIT(7));
+ if (efuse_data)
+ return -2;
+
+ efuse_data = __adie_efuse_read_bits(BLK_ADC_DETA_ABC_OTP * BLK_WIDTH_OTP_EMEMORY, 16);
+#elif defined(CONFIG_ARCH_SCX30G) || defined(CONFIG_ARCH_SCX35L)
+ efuse_data = __ddie_efuse_read(BLK_ADC_DETA_ABC);
+ WARN_ON(!(efuse_data & BIT(31))); /* BIT 31 is protected bit */
+#else
+ #warning "AuxADC CAL DETA need fixing"
+#endif
+
+ pr_info("%s efuse data: 0x%08x\n", __func__, efuse_data);
+
+ efuse_data &= 0xFFFFFF; /* get BIT0 ~ BIT23 in block 7 */
+
+ if (!(efuse_data) || (!pdata)) {
+ return -1;
+ }
+
+ //WARN_ON(!((delta[0] > delta[1]) && (delta[1] > delta[2])));
+
+ for (i = 0; i < num; i++) {
+ pdata[i] =
+ (unsigned int)ADC_VOL(delta[i], ideal[i][1], ideal[i][0]);
+ }
+
+ /* dump adc calibration parameters */
+ printk("%s adc_cal: ", __func__);
+ for (i = 0; i < num; i++) {
+ printk("%d -- %d; \n", (pdata[i] & 0xFFFF),
+ (pdata[i] >> 16) & 0xFFFF);
+ }
+ printk("\n");
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_get_cal);
+
+/*
+ * sci_efuse_get_cal_v2 - read 4 point adc calibration data saved in efuse
+ * @pdata: adc data pointer
+ * pdata[0] -> 4.2v
+ * pdata[1] -> 3.6v
+ * pdata[3] -> 0.9v
+ * pdata[4] -> 0.3v
+ * @num: the length of adc data
+ *
+ * retruns 0 if success, else
+ * returns negative number.
+ */
+int sci_efuse_get_cal_v2(unsigned int *pdata, int num)
+{
+ int i;
+ u32 efuse_data;
+ u8 *delta = (u8 *) & efuse_data;
+ const u16 ideal[4][2] = {
+ {4200, 830}, /* FIXME: efuse only support 10bits */
+ {3600, 711},
+ {900, 737},
+ {300, 255},
+ };
+
+ efuse_data = __ddie_efuse_read(BLK_ADC_DETA_ABC);
+
+ pr_info("%s efuse block(%d) data: 0x%08x\n", __func__, BLK_ADC_DETA_ABC, efuse_data);
+
+ WARN_ON(!(efuse_data & BIT(31))); /* BIT 31 is protected bit */
+ efuse_data &= 0xFFFFFF; /* get BIT0 ~ BIT23 in block 7 */
+
+ if (!(efuse_data) || (!pdata)) {
+ return -1;
+ }
+
+ WARN_ON(!((delta[0] > delta[1]) && (delta[1] > delta[2])));
+
+ for (i = 0; i < num; i++) {
+ pdata[i] =
+ (unsigned int)ADC_VOL(delta[i], ideal[i][1], ideal[i][0]);
+ if (3 == i) {
+ efuse_data = __ddie_efuse_read(BLK_ADC_DETA_D);
+ pr_info("efuse block(%d) data: 0x%08x\n", BLK_ADC_DETA_D, efuse_data);
+ WARN_ON(!(efuse_data & BIT(31)));
+ efuse_data &= 0xFF0000; /* get BIT16 ~ BIT23 in block 9 */
+ if (!(efuse_data)) {
+ return -2;
+ }
+ pdata[i] =
+ (unsigned int)ADC_VOL(delta[2], ideal[i][1],
+ ideal[i][0]);
+ }
+ }
+
+ /* dump adc calibration parameters */
+ printk("%s adc_cal: ", __func__);
+ for (i = 0; i < num; i++) {
+ printk("%d -- %d; \n", (pdata[i] & 0xFFFF),
+ (pdata[i] >> 16) & 0xFFFF);
+ }
+ printk("\n");
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sci_efuse_get_cal_v2);
+
+/*
+* sci_efuse_get_cal_v3 - read 2 point adc calibration data saved in efuse
+* @pdata: adc data pointer
+* pdata[0] -> 0.9v
+* pdata[1] -> 0.3v
+* @num: the length of adc data
+*
+* retruns 0 if success, else
+* returns negative number.
+*/
+int sci_efuse_get_cal_v3(unsigned int *pdata, int num)
+{
+ int i;
+ u32 efuse_data;
+ u8 *delta = (u8 *) & efuse_data;
+ const u16 ideal[2][2] = {
+ {900, 737},
+ {300, 245},
+ };
+ if (!pdata || num < 2) {
+ return -1;
+ }
+ efuse_data = __ddie_efuse_read(BLK_ADC_DETA_ABC);
+ pr_info("%s efuse block(%d) data: 0x%08x\n", __func__, BLK_ADC_DETA_ABC, efuse_data);
+ WARN_ON(!(efuse_data & BIT(31)));
+ /* BIT 31 is protected bit */
+ efuse_data &= 0xFF0000;
+ /* get BIT16 ~ BIT23 in block 7 */
+ if (!efuse_data) {
+ return -2;
+ }
+ pdata[0] = (unsigned int)ADC_VOL(delta[2], ideal[0][1], ideal[0][0]);
+ efuse_data = __ddie_efuse_read(BLK_ADC_DETA_D);
+ pr_info("efuse block(%d) data: 0x%08x\n", BLK_ADC_DETA_D, efuse_data);
+ WARN_ON(!(efuse_data & BIT(31)));
+ efuse_data &= 0xFF0000;
+ /* get BIT16 ~ BIT23 in block 9 */
+ if (!(efuse_data)) {
+ return -3;
+ }
+ pdata[1] = (unsigned int)ADC_VOL(delta[2], ideal[1][1],ideal[1][0]);
+ /* dump adc calibration parameters */
+ printk("%s adc_cal: \n", __func__);
+ for (i = 0; i < num; i++) {
+ printk("%d -- %d; \n", (pdata[i] & 0xFFFF),
+ (pdata[i] >> 16) & 0xFFFF);
+ }
+ printk("\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sci_efuse_get_cal_v3);
+
+#if defined(CONFIG_ADIE_SC2723) || defined(CONFIG_ADIE_SC2723S)
+
+int sci_efuse_ib_trim_get(unsigned int *p_cal_data)
+{
+ unsigned int data,blk0;
+
+ blk0 = __adie_efuse_read(0);
+ if (blk0 & (1 << 7)) {
+ return 0;
+ }
+
+ data = __adie_efuse_read_bits(BITSINDEX(15, 0), 7);
+ *p_cal_data = data;
+ return 1;
+}
+EXPORT_SYMBOL_GPL(sci_efuse_ib_trim_get);
+
+#endif