Home | History | Annotate | Download | only in pmic
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2011-2013
      4  * Texas Instruments, <www.ti.com>
      5  */
      6 
      7 #include <common.h>
      8 #include <i2c.h>
      9 #include <linux/errno.h>
     10 #include <power/pmic.h>
     11 #include <power/tps65218.h>
     12 
     13 int tps65218_reg_read(uchar dest_reg, uchar *dest_val)
     14 {
     15 	uchar read_val;
     16 	int ret;
     17 
     18 	ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
     19 	if (ret)
     20 		return ret;
     21 
     22 	*dest_val = read_val;
     23 
     24 	return 0;
     25 }
     26 
     27 /**
     28  *  tps65218_reg_write() - Generic function that can write a TPS65218 PMIC
     29  *			   register or bit field regardless of protection
     30  *			   level.
     31  *
     32  *  @prot_level:	   Register password protection.  Use
     33  *			   TPS65218_PROT_LEVEL_NONE,
     34  *			   TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2
     35  *  @dest_reg:		   Register address to write.
     36  *  @dest_val:		   Value to write.
     37  *  @mask:		   Bit mask (8 bits) to be applied.  Function will only
     38  *			   change bits that are set in the bit mask.
     39  *
     40  *  @return:		   0 for success, not 0 on failure, as per the i2c API
     41  */
     42 int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val,
     43 		       uchar mask)
     44 {
     45 	uchar read_val;
     46 	uchar xor_reg;
     47 	int ret;
     48 
     49 	/*
     50 	 * If we are affecting only a bit field, read dest_reg and apply the
     51 	 * mask
     52 	 */
     53 	if (mask != TPS65218_MASK_ALL_BITS) {
     54 		ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1);
     55 		if (ret)
     56 			return ret;
     57 		read_val &= (~mask);
     58 		read_val |= (dest_val & mask);
     59 		dest_val = read_val;
     60 	}
     61 
     62 	if (prot_level > 0) {
     63 		xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK;
     64 		ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
     65 				&xor_reg, 1);
     66 		if (ret)
     67 			return ret;
     68 	}
     69 
     70 	ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
     71 	if (ret)
     72 		return ret;
     73 
     74 	if (prot_level == TPS65218_PROT_LEVEL_2) {
     75 		ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1,
     76 				&xor_reg, 1);
     77 		if (ret)
     78 			return ret;
     79 
     80 		ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1);
     81 		if (ret)
     82 			return ret;
     83 	}
     84 
     85 	return 0;
     86 }
     87 
     88 /**
     89  * tps65218_voltage_update() - Function to change a voltage level, as this
     90  *			       is a multi-step process.
     91  * @dc_cntrl_reg:	       DC voltage control register to change.
     92  * @volt_sel:		       New value for the voltage register
     93  * @return:		       0 for success, not 0 on failure.
     94  */
     95 int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel)
     96 {
     97 	if ((dc_cntrl_reg != TPS65218_DCDC1) &&
     98 	    (dc_cntrl_reg != TPS65218_DCDC2) &&
     99 	    (dc_cntrl_reg != TPS65218_DCDC3))
    100 		return 1;
    101 
    102 	/* set voltage level */
    103 	if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel,
    104 			       TPS65218_DCDC_VSEL_MASK))
    105 		return 1;
    106 
    107 	/* set GO bit to initiate voltage transition */
    108 	if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW,
    109 			       TPS65218_DCDC_GO, TPS65218_DCDC_GO))
    110 		return 1;
    111 
    112 	return 0;
    113 }
    114 
    115 /**
    116  * tps65218_toggle_fseal() - Perform the sequence that toggles the FSEAL bit.
    117  *
    118  * @return:		     0 on success, -EBADE if the sequence was broken
    119  */
    120 int tps65218_toggle_fseal(void)
    121 {
    122 	if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
    123 			       0xb1, TPS65218_MASK_ALL_BITS))
    124 		return -EBADE;
    125 
    126 	if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
    127 			       0xfe, TPS65218_MASK_ALL_BITS))
    128 		return -EBADE;
    129 
    130 	if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD,
    131 			       0xa3, TPS65218_MASK_ALL_BITS))
    132 		return -EBADE;
    133 
    134 	return 0;
    135 }
    136 
    137 /**
    138  * tps65218_lock_fseal() - Perform the sequence that locks the FSEAL bit to 1.
    139  *
    140  * The FSEAL bit prevents the PMIC from turning off DCDC5 and DCDC6. It can be
    141  * toggled at most 3 times: 0->1, 1->0, and finally 0->1. After the third switch
    142  * its value is locked and can only be reset by powering off the PMIC entirely.
    143  *
    144  * @return:		   0 on success, -EBADE if the sequence was broken
    145  */
    146 int tps65218_lock_fseal(void)
    147 {
    148 	int i;
    149 
    150 	for (i = 0; i < 3; i++)
    151 		if (tps65218_toggle_fseal())
    152 			return -EBADE;
    153 
    154 	return 0;
    155 }
    156 
    157 int power_tps65218_init(unsigned char bus)
    158 {
    159 	static const char name[] = "TPS65218_PMIC";
    160 	struct pmic *p = pmic_alloc();
    161 
    162 	if (!p) {
    163 		printf("%s: POWER allocation error!\n", __func__);
    164 		return -ENOMEM;
    165 	}
    166 
    167 	p->name = name;
    168 	p->interface = PMIC_I2C;
    169 	p->number_of_regs = TPS65218_PMIC_NUM_OF_REGS;
    170 	p->hw.i2c.addr = TPS65218_CHIP_PM;
    171 	p->hw.i2c.tx_num = 1;
    172 	p->bus = bus;
    173 
    174 	return 0;
    175 }
    176