mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			513 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			513 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright (c) 2021 Nuvoton Technology Corp.
 | |
|  */
 | |
| 
 | |
| #include <clk.h>
 | |
| #include <common.h>
 | |
| #include <dm.h>
 | |
| #include <errno.h>
 | |
| #include <fuse.h>
 | |
| #include <asm/io.h>
 | |
| #include <linux/delay.h>
 | |
| #include <asm/arch/otp.h>
 | |
| 
 | |
| struct npcm_otp_priv {
 | |
| 	struct npcm_otp_regs *regs[2];
 | |
| };
 | |
| 
 | |
| static struct npcm_otp_priv *otp_priv;
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_check_inputs                                     */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr - fuse array number to check                          */
 | |
| /*                  word - fuse word (offset) to check                        */
 | |
| /* Returns:         int                                                       */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Checks is arr and word are illegal and do not exceed      */
 | |
| /*                  their range. Return 0 if they are legal, -1 if not        */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static int npcm_otp_check_inputs(u32 arr, u32 word)
 | |
| {
 | |
| 	if (arr >= NPCM_NUM_OF_SA) {
 | |
| 		if (IS_ENABLED(CONFIG_ARCH_NPCM8XX))
 | |
| 			printf("\nError: npcm8XX otp includs only one bank: 0\n");
 | |
| 		if (IS_ENABLED(CONFIG_ARCH_NPCM7XX))
 | |
| 			printf("\nError: npcm7XX otp includs only two banks: 0 and 1\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if (word >= NPCM_OTP_ARR_BYTE_SIZE) {
 | |
| 		printf("\nError: npcm otp array comprises only %d bytes, numbered from 0 to %d\n",
 | |
| 		       NPCM_OTP_ARR_BYTE_SIZE, NPCM_OTP_ARR_BYTE_SIZE - 1);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_wait_for_otp_ready                               */
 | |
| /*                                                                            */
 | |
| /* Parameters:      array - fuse array to wait for                            */
 | |
| /* Returns:         int                                                       */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Initialize the Fuse HW module.                            */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static int npcm_otp_wait_for_otp_ready(u32 arr, u32 timeout)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs = otp_priv->regs[arr];
 | |
| 	u32 time = timeout;
 | |
| 
 | |
| 	/*------------------------------------------------------------------------*/
 | |
| 	/* check parameters validity                                              */
 | |
| 	/*------------------------------------------------------------------------*/
 | |
| 	if (arr > NPCM_FUSE_SA)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	while (--time > 1) {
 | |
| 		if (readl(®s->fst) & FST_RDY) {
 | |
| 			/* fuse is ready, clear the status. */
 | |
| 			writel(readl(®s->fst) | FST_RDST, ®s->fst);
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* try to clear the status in case it was set */
 | |
| 	writel(readl(®s->fst) | FST_RDST, ®s->fst);
 | |
| 
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_read_byte                                        */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr  - Storage Array type [input].                        */
 | |
| /*                  addr - Byte-address to read from [input].                 */
 | |
| /*                  data - Pointer to result [output].                        */
 | |
| /* Returns:         none                                                      */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Read 8-bit data from an OTP storage array.                */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static void npcm_otp_read_byte(u32 arr, u32 addr, u8 *data)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs = otp_priv->regs[arr];
 | |
| 
 | |
| 	/* Wait for the Fuse Box Idle */
 | |
| 	npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 	/* Configure the byte address in the fuse array for read operation */
 | |
| 	writel(FADDR_VAL(addr, 0), ®s->faddr);
 | |
| 
 | |
| 	/* Initiate a read cycle */
 | |
| 	writel(READ_INIT, ®s->fctl);
 | |
| 
 | |
| 	/* Wait for read operation completion */
 | |
| 	npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 	/* Read the result */
 | |
| 	*data = readl(®s->fdata) & FDATA_MASK;
 | |
| 
 | |
| 	/* Clean FDATA contents to prevent unauthorized software from reading
 | |
| 	 * sensitive information
 | |
| 	 */
 | |
| 	writel(FDATA_CLEAN_VALUE, ®s->fdata);
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_bit_is_programmed                                */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr     - Storage Array type [input].                     */
 | |
| /*                  byte_offset - Byte offset in array [input].               */
 | |
| /*                  bit_offset  - Bit offset in byte [input].                 */
 | |
| /* Returns:         Nonzero if bit is programmed, zero otherwise.             */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Check if a bit is programmed in an OTP storage array.     */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static bool npcm_otp_bit_is_programmed(u32  arr,
 | |
| 				       u32 byte_offset, u8 bit_offset)
 | |
| {
 | |
| 	u32 data = 0;
 | |
| 
 | |
| 	/* Read the entire byte you wish to program */
 | |
| 	npcm_otp_read_byte(arr, byte_offset, (u8 *)&data);
 | |
| 
 | |
| 	/* Check whether the bit is already programmed */
 | |
| 	if (data & (1 << bit_offset))
 | |
| 		return true;
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_program_bit                                      */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr     - Storage Array type [input].                     */
 | |
| /*                  byte)offset - Byte offset in array [input].               */
 | |
| /*                  bit_offset  - Bit offset in byte [input].                 */
 | |
| /* Returns:         int                                                       */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Program (set to 1) a bit in an OTP storage array.         */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static int npcm_otp_program_bit(u32 arr, u32 byte_offset,
 | |
| 				u8 bit_offset)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs = otp_priv->regs[arr];
 | |
| 	int count;
 | |
| 	u8 read_data;
 | |
| 
 | |
| 	/* Wait for the Fuse Box Idle */
 | |
| 	npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 	/* Make sure the bit is not already programmed */
 | |
| 	if (npcm_otp_bit_is_programmed(arr, byte_offset, bit_offset))
 | |
| 		return 0;
 | |
| 
 | |
| 	/* Configure the bit address in the fuse array for program operation */
 | |
| 	writel(FADDR_VAL(byte_offset, bit_offset), ®s->faddr);
 | |
| 	writel(readl(®s->faddr) | FADDR_IN_PROG, ®s->faddr);
 | |
| 
 | |
| 	// program up to MAX_PROGRAM_PULSES
 | |
| 	for (count = 1; count <= MAX_PROGRAM_PULSES; count++) {
 | |
| 		/* Initiate a program cycle */
 | |
| 		writel(PROGRAM_ARM, ®s->fctl);
 | |
| 		writel(PROGRAM_INIT, ®s->fctl);
 | |
| 
 | |
| 		/* Wait for program operation completion */
 | |
| 		npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 		// after MIN_PROGRAM_PULSES start verifying the result
 | |
| 		if (count >= MIN_PROGRAM_PULSES) {
 | |
| 			/* Initiate a read cycle */
 | |
| 			writel(READ_INIT, ®s->fctl);
 | |
| 
 | |
| 			/* Wait for read operation completion */
 | |
| 			npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 			/* Read the result */
 | |
| 			read_data = readl(®s->fdata) & FDATA_MASK;
 | |
| 
 | |
| 			/* If the bit is set the sequence ended correctly */
 | |
| 			if (read_data & (1 << bit_offset))
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// check if programmking failed
 | |
| 	if (count > MAX_PROGRAM_PULSES) {
 | |
| 		printf("program fail\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Clean FDATA contents to prevent unauthorized software from reading
 | |
| 	 * sensitive information
 | |
| 	 */
 | |
| 	writel(FDATA_CLEAN_VALUE, ®s->fdata);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_program_byte                                     */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr     - Storage Array type [input].                     */
 | |
| /*                  byte_offset - Byte offset in array [input].               */
 | |
| /*                  value   - Byte to program [input].                        */
 | |
| /* Returns:         int                                                       */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Program (set to 1) a given byte's relevant bits in an     */
 | |
| /*                  OTP storage array.                                        */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| static int npcm_otp_program_byte(u32 arr, u32 byte_offset,
 | |
| 				 u8 value)
 | |
| {
 | |
| 	int status = 0;
 | |
| 	unsigned int i;
 | |
| 	u8 data = 0;
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = npcm_otp_check_inputs(arr, byte_offset);
 | |
| 	if (rc != 0)
 | |
| 		return rc;
 | |
| 
 | |
| 	/* Wait for the Fuse Box Idle */
 | |
| 	npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
 | |
| 
 | |
| 	/* Read the entire byte you wish to program */
 | |
| 	npcm_otp_read_byte(arr, byte_offset, &data);
 | |
| 
 | |
| 	/* In case all relevant bits are already programmed - nothing to do */
 | |
| 	if ((~data & value) == 0)
 | |
| 		return status;
 | |
| 
 | |
| 	/* Program unprogrammed bits. */
 | |
| 	for (i = 0; i < 8; i++) {
 | |
| 		if (value & (1 << i)) {
 | |
| 			/* Program (set to 1) the relevant bit */
 | |
| 			int last_status = npcm_otp_program_bit(arr, byte_offset, (u8)i);
 | |
| 
 | |
| 			if (last_status != 0)
 | |
| 				status = last_status;
 | |
| 		}
 | |
| 	}
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_is_fuse_array_disabled                           */
 | |
| /*                                                                            */
 | |
| /* Parameters:      arr - Storage Array type [input].                         */
 | |
| /* Returns:         bool                                                      */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Return true if access to the first 2048 bits of the       */
 | |
| /*                  specified fuse array is disabled, false if not            */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| bool npcm_otp_is_fuse_array_disabled(u32 arr)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs = otp_priv->regs[arr];
 | |
| 
 | |
| 	return (readl(®s->fcfg) & FCFG_FDIS) != 0;
 | |
| }
 | |
| 
 | |
| int npcm_otp_select_key(u8 key_index)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs = otp_priv->regs[NPCM_KEY_SA];
 | |
| 	u32 idx = 0;
 | |
| 	u32 time = 0xDAEDBEEF;
 | |
| 
 | |
| 	if (key_index >= 4)
 | |
| 		return -1;
 | |
| 
 | |
| 	/* Do not destroy ECCDIS bit */
 | |
| 	idx = readl(®s->fustrap_fkeyind);
 | |
| 
 | |
| 	/* Configure the key size */
 | |
| 	idx &= ~FKEYIND_KSIZE_MASK;
 | |
| 	idx |= FKEYIND_KSIZE_256;
 | |
| 
 | |
| 	/* Configure the key index (0 to 3) */
 | |
| 	idx &= ~FKEYIND_KIND_MASK;
 | |
| 	idx |= FKEYIND_KIND_KEY(key_index);
 | |
| 
 | |
| 	writel(idx, ®s->fustrap_fkeyind);
 | |
| 
 | |
| 	/* Wait for selection completetion */
 | |
| 	while (--time > 1) {
 | |
| 		if (readl(®s->fustrap_fkeyind) & FKEYIND_KVAL)
 | |
| 			return 0;
 | |
| 		udelay(1);
 | |
| 	}
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_nibble_parity_ecc_encode                         */
 | |
| /*                                                                            */
 | |
| /* Parameters:      datain - pointer to decoded data buffer                   */
 | |
| /*                  dataout - pointer to encoded data buffer (buffer size     */
 | |
| /*                            should be 2 x dataout)                          */
 | |
| /*                  size - size of encoded data (decoded data x 2)            */
 | |
| /* Returns:         none                                                      */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Decodes the data according to nibble parity ECC scheme.   */
 | |
| /*                  Size specifies the encoded data size.                     */
 | |
| /*                  Decodes whole bytes only                                  */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| void npcm_otp_nibble_parity_ecc_encode(u8 *datain, u8 *dataout, u32 size)
 | |
| {
 | |
| 	u32 i, idx;
 | |
| 	u8 E0, E1, E2, E3;
 | |
| 
 | |
| 	for (i = 0; i < (size / 2); i++) {
 | |
| 		E0 = (datain[i] >> 0) & 0x01;
 | |
| 		E1 = (datain[i] >> 1) & 0x01;
 | |
| 		E2 = (datain[i] >> 2) & 0x01;
 | |
| 		E3 = (datain[i] >> 3) & 0x01;
 | |
| 
 | |
| 		idx = i * 2;
 | |
| 		dataout[idx] = datain[i] & 0x0f;
 | |
| 		dataout[idx] |= (E0 ^ E1) << 4;
 | |
| 		dataout[idx] |= (E2 ^ E3) << 5;
 | |
| 		dataout[idx] |= (E0 ^ E2) << 6;
 | |
| 		dataout[idx] |= (E1 ^ E3) << 7;
 | |
| 
 | |
| 		E0 = (datain[i] >> 4) & 0x01;
 | |
| 		E1 = (datain[i] >> 5) & 0x01;
 | |
| 		E2 = (datain[i] >> 6) & 0x01;
 | |
| 		E3 = (datain[i] >> 7) & 0x01;
 | |
| 
 | |
| 		idx = i * 2 + 1;
 | |
| 		dataout[idx] = (datain[i] & 0xf0) >> 4;
 | |
| 		dataout[idx] |= (E0 ^ E1) << 4;
 | |
| 		dataout[idx] |= (E2 ^ E3) << 5;
 | |
| 		dataout[idx] |= (E0 ^ E2) << 6;
 | |
| 		dataout[idx] |= (E1 ^ E3) << 7;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        npcm_otp_majority_rule_ecc_encode                         */
 | |
| /*                                                                            */
 | |
| /* Parameters:      datain - pointer to decoded data buffer                   */
 | |
| /*                  dataout - pointer to encoded data buffer (buffer size     */
 | |
| /*                            should be 3 x dataout)                          */
 | |
| /*                  size - size of encoded data (decoded data x 3)            */
 | |
| /* Returns:         none                                                      */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Decodes the data according to Major Rule ECC scheme.      */
 | |
| /*                  Size specifies the encoded data size.                     */
 | |
| /*                  Decodes whole bytes only                                  */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| void npcm_otp_majority_rule_ecc_encode(u8 *datain, u8 *dataout, u32 size)
 | |
| {
 | |
| 	u32 byte;
 | |
| 	u32 bit;
 | |
| 	u8 bit_val;
 | |
| 	u32 decoded_size = size / 3;
 | |
| 
 | |
| 	for (byte = 0; byte < decoded_size; byte++) {
 | |
| 		for (bit = 0; bit < 8; bit++) {
 | |
| 			bit_val = (datain[byte] >> bit) & 0x01;
 | |
| 
 | |
| 			if (bit_val) {
 | |
| 				dataout[byte] |= (1 << bit);
 | |
| 				dataout[decoded_size + byte] |= (1 << bit);
 | |
| 				dataout[decoded_size * 2 + byte] |= (1 << bit);
 | |
| 			} else {
 | |
| 				dataout[byte] &= ~(1 << bit);
 | |
| 				dataout[decoded_size + byte] &= ~(1 << bit);
 | |
| 				dataout[decoded_size * 2 + byte] &= ~(1 << bit);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*----------------------------------------------------------------------------*/
 | |
| /* Function:        fuse_program_data                                         */
 | |
| /*                                                                            */
 | |
| /* Parameters:      bank - Storage Array type [input].                        */
 | |
| /*                  word - Byte offset in array [input].                      */
 | |
| /*                  data - Pointer to data buffer to program.                 */
 | |
| /*                  size - Number of bytes to program.                        */
 | |
| /* Returns:         none                                                      */
 | |
| /* Side effects:                                                              */
 | |
| /* Description:     Programs the given byte array (size bytes) to the given   */
 | |
| /*                  OTP storage array, starting from offset word.             */
 | |
| /*----------------------------------------------------------------------------*/
 | |
| int fuse_program_data(u32 bank, u32 word, u8 *data, u32 size)
 | |
| {
 | |
| 	u32 arr = (u32)bank;
 | |
| 	u32 byte;
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = npcm_otp_check_inputs(bank, word + size - 1);
 | |
| 	if (rc != 0)
 | |
| 		return rc;
 | |
| 
 | |
| 	for (byte = 0; byte < size; byte++) {
 | |
| 		u8 val;
 | |
| 
 | |
| 		val = data[byte];
 | |
| 		if (val == 0) // optimization
 | |
| 			continue;
 | |
| 
 | |
| 		rc = npcm_otp_program_byte(arr, word + byte, data[byte]);
 | |
| 		if (rc != 0)
 | |
| 			return rc;
 | |
| 
 | |
| 		// verify programming of every '1' bit
 | |
| 		val = 0;
 | |
| 		npcm_otp_read_byte((u32)bank, byte, &val);
 | |
| 		if ((data[byte] & ~val) != 0)
 | |
| 			return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int fuse_prog_image(u32 bank, uintptr_t address)
 | |
| {
 | |
| 	return fuse_program_data(bank, 0, (u8 *)address, NPCM_OTP_ARR_BYTE_SIZE);
 | |
| }
 | |
| 
 | |
| int fuse_read(u32 bank, u32 word, u32 *val)
 | |
| {
 | |
| 	int rc = npcm_otp_check_inputs(bank, word);
 | |
| 
 | |
| 	if (rc != 0)
 | |
| 		return rc;
 | |
| 
 | |
| 	*val = 0;
 | |
| 	npcm_otp_read_byte((u32)bank, word, (u8 *)val);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int fuse_sense(u32 bank, u32 word, u32 *val)
 | |
| {
 | |
| 	/* We do not support overriding */
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| int fuse_prog(u32 bank, u32 word, u32 val)
 | |
| {
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = npcm_otp_check_inputs(bank, word);
 | |
| 	if (rc != 0)
 | |
| 		return rc;
 | |
| 
 | |
| 	return npcm_otp_program_byte(bank, word, (u8)val);
 | |
| }
 | |
| 
 | |
| int fuse_override(u32 bank, u32 word, u32 val)
 | |
| {
 | |
| 	/* We do not support overriding */
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| static int npcm_otp_bind(struct udevice *dev)
 | |
| {
 | |
| 	struct npcm_otp_regs *regs;
 | |
| 
 | |
| 	otp_priv = calloc(1, sizeof(struct npcm_otp_priv));
 | |
| 	if (!otp_priv)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	regs = dev_remap_addr_index(dev, 0);
 | |
| 	if (!regs) {
 | |
| 		printf("Cannot find reg address (arr #0), binding failed\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 	otp_priv->regs[0] = regs;
 | |
| 
 | |
| 	if (IS_ENABLED(CONFIG_ARCH_NPCM7xx)) {
 | |
| 		regs = dev_remap_addr_index(dev, 1);
 | |
| 		if (!regs) {
 | |
| 			printf("Cannot find reg address (arr #1), binding failed\n");
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 		otp_priv->regs[1] = regs;
 | |
| 	}
 | |
| 	printf("OTP: NPCM OTP module bind OK\n");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct udevice_id npcm_otp_ids[] = {
 | |
| 	{ .compatible = "nuvoton,npcm845-otp" },
 | |
| 	{ .compatible = "nuvoton,npcm750-otp" },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(npcm_otp) = {
 | |
| 	.name = "npcm_otp",
 | |
| 	.id = UCLASS_MISC,
 | |
| 	.of_match = npcm_otp_ids,
 | |
| 	.priv_auto = sizeof(struct npcm_otp_priv),
 | |
| 	.bind = npcm_otp_bind,
 | |
| };
 |