view target-utils/libbase/abbdrv.c @ 999:30fad2b3afd2

doc/Flash-write-protection: document flash lock-state retrieval
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 04 Dec 2023 20:40:50 +0000
parents a04a145098f1
children
line wrap: on
line source

/* Driver for Analog Baseband Circuit (TWL3025) */
/* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */

/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
 *
 * 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 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "types.h"
#include "abbdefs.h"

/* TWL3025, modified for page 2 support */
#define REG_PAGE(n)	((n) >> 6)
#define REG_ADDR(n)	((n) & 0x1f)

#define TWL3025_DEV_IDX		0	/* On the SPI bus */
#define TWL3025_TSP_DEV_IDX	0	/* On the TSP bus */

int abb_state_initdone, abb_state_page;

void
abb_reg_write(reg, data)
{
	u16 tx;

	if (reg != PAGEREG && REG_PAGE(reg) != abb_state_page)
		abb_select_page(REG_PAGE(reg));

	tx = ((data & 0x3ff) << 6) | (REG_ADDR(reg) << 1);

	spi_xfer(TWL3025_DEV_IDX, 16, &tx, 0);
}

u16
abb_reg_read(reg)
{
	u16 tx, rx;

	if (REG_PAGE(reg) != abb_state_page)
		abb_select_page(REG_PAGE(reg));

	tx = (REG_ADDR(reg) << 1) | 1;

	/* A read cycle contains two SPI transfers */
	spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
	/* delay of seven 13MHz cycles */
	wait_ARM_cycles(7);
	spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);

	rx >>= 6;

	return rx;
}

/* Switch the register page of the TWL3025 */
abb_select_page(page)
{
	switch (page) {
	case 0:
		abb_reg_write(PAGEREG, 1 << 0);
		break;
	case 1:
		abb_reg_write(PAGEREG, 1 << 1);
		break;
	case 2:
		/* not documented in datasheet, learned from TCS211 code */
		abb_reg_write(PAGEREG, 1 << 4);
		break;
	}
	abb_state_page = page;
	return(0);
}

abb_init()
{
	if (abb_state_initdone)
		return(0);
	spi_init();
	abb_select_page(0);
	/* CLK13M enable */
	abb_reg_write(TOGBR2, TOGBR2_ACTS);
	/* ABB_Wait_IBIC_Access() delay of 210 us */
	wait_ARM_cycles(210 * 13);
	/* for whatever reason we need to do this twice */
	abb_reg_write(TOGBR2, TOGBR2_ACTS);
	/* ABB_Wait_IBIC_Access() delay of 210 us */
	wait_ARM_cycles(210 * 13);
	abb_state_initdone = 1;
	return(1);
}

void
abb_unlock_page2()
{
	abb_reg_write(TAPCTRL, 0x01);
	abb_reg_write(TAPREG,  0x1B);
}

void
abb_power_off()
{
	abb_init();
	/*
	 * If we booted via nTESTRESET, we need to clean up some state
	 * in a secret undocumented Iota register before we do the DEVOFF,
	 * otherwise subsequent switch-on via regular PWON button
	 * won't work correctly.
	 */
	abb_unlock_page2();
	abb_reg_write(VRPCAUX, 0x07);
	serial_flush();
	abb_reg_write(VRPCDEV, 0x01);	/* DEVOFF */
	/*
	 * TWL3025 datasheet seems to indicate that the time for the DEVOFF
	 * command to take effect is 5 cycles of the 32.768 kHz clock.
	 * We'll do an ARM-timed delay of 10 ms before returning from
	 * this function.
	 */
	wait_ARM_cycles(13000 * 10);
}