blob: aaab27e138affc5101f7338503faf6df86f3d727 [file] [log] [blame]
/* Copyright 2015 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* SPI module for Chrome EC */
#include "clock.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
#include "spi.h"
#include "task.h"
#include "timer.h"
#include "util.h"
/* Console output macros */
#define CPUTS(outstr) cputs(CC_SPI, outstr)
#define CPRINTS(format, args...) cprints(CC_SPI, format, ##args)
enum sspi_clk_sel {
sspi_clk_24mhz = 0,
sspi_clk_12mhz,
sspi_clk_8mhz,
sspi_clk_6mhz,
sspi_clk_4p8mhz,
sspi_clk_4mhz,
sspi_clk_3p428mhz,
sspi_clk_3mhz,
};
enum sspi_ch_sel {
SSPI_CH_CS0 = 0,
SSPI_CH_CS1,
};
static void sspi_frequency(enum sspi_clk_sel freq)
{
/*
* bit[6:5]
* Bit 6:Clock Polarity (CLPOL)
* 0: SSCK is low in the idle mode.
* 1: SSCK is high in the idle mode.
* Bit 5:Clock Phase (CLPHS)
* 0: Latch data on the first SSCK edge.
* 1: Latch data on the second SSCK edge.
*
* bit[4:2]
* 000b: 1/2 clk_sspi
* 001b: 1/4 clk_sspi
* 010b: 1/6 clk_sspi
* 011b: 1/8 clk_sspi
* 100b: 1/10 clk_sspi
* 101b: 1/12 clk_sspi
* 110b: 1/14 clk_sspi
* 111b: 1/16 clk_sspi
*
* SSCK frequency is [freq] MHz and mode 3.
* note, clk_sspi need equal to 48MHz above.
*/
IT83XX_SSPI_SPICTRL1 |= (0x60 | (freq << 2));
}
static void sspi_transmission_end(void)
{
/* Write 1 to end the SPI transmission. */
IT83XX_SSPI_SPISTS = 0x20;
/* Short delay for "Transfer End Flag" */
IT83XX_GCTRL_WNCKR = 0;
/* Write 1 to clear this bit and terminate data transmission. */
IT83XX_SSPI_SPISTS = 0x02;
}
/* We assume only one SPI port in the chip, one SPI device */
int spi_enable(const struct spi_device_t *spi_device, int enable)
{
int port = spi_device->port;
if (enable) {
/*
* bit[5:4]
* 00b: SPI channel 0 and channel 1 are disabled.
* 10b: SSCK/SMOSI/SMISO/SSCE1# are enabled.
* 01b: SSCK/SMOSI/SMISO/SSCE0# are enabled.
* 11b: SSCK/SMOSI/SMISO/SSCE1#/SSCE0# are enabled.
*/
if (port == SSPI_CH_CS1)
IT83XX_GPIO_GRC1 |= 0x20;
else
IT83XX_GPIO_GRC1 |= 0x10;
gpio_config_module(MODULE_SPI_CONTROLLER, 1);
} else {
if (port == SSPI_CH_CS1)
IT83XX_GPIO_GRC1 &= ~0x20;
else
IT83XX_GPIO_GRC1 &= ~0x10;
gpio_config_module(MODULE_SPI_CONTROLLER, 0);
}
return EC_SUCCESS;
}
int spi_transaction(const struct spi_device_t *spi_device,
const uint8_t *txdata, int txlen, uint8_t *rxdata,
int rxlen)
{
int idx;
uint8_t port = spi_device->port;
static struct mutex spi_mutex;
mutex_lock(&spi_mutex);
/* bit[0]: Write cycle */
IT83XX_SSPI_SPICTRL2 &= ~0x04;
for (idx = 0x00; idx < txlen; idx++) {
IT83XX_SSPI_SPIDATA = txdata[idx];
if (port == SSPI_CH_CS1)
/* Write 1 to start the data transmission of CS1 */
IT83XX_SSPI_SPISTS |= 0x08;
else
/* Write 1 to start the data transmission of CS0 */
IT83XX_SSPI_SPISTS |= 0x10;
}
/* bit[1]: Read cycle */
IT83XX_SSPI_SPICTRL2 |= 0x04;
for (idx = 0x00; idx < rxlen; idx++) {
if (port == SSPI_CH_CS1)
/* Write 1 to start the data transmission of CS1 */
IT83XX_SSPI_SPISTS |= 0x08;
else
/* Write 1 to start the data transmission of CS0 */
IT83XX_SSPI_SPISTS |= 0x10;
rxdata[idx] = IT83XX_SSPI_SPIDATA;
}
sspi_transmission_end();
mutex_unlock(&spi_mutex);
return EC_SUCCESS;
}
static void sspi_init(void)
{
int i;
clock_enable_peripheral(CGC_OFFSET_SSPI, 0, 0);
sspi_frequency(sspi_clk_8mhz);
/*
* bit[5:3] Byte Width (BYTEWIDTH)
* 000b: 8-bit transmission
* 001b: 1-bit transmission
* 010b: 2-bit transmission
* 011b: 3-bit transmission
* 100b: 4-bit transmission
* 101b: 5-bit transmission
* 110b: 6-bit transmission
* 111b: 7-bit transmission
*
* bit[1] Blocking selection
*/
IT83XX_SSPI_SPICTRL2 |= 0x02;
for (i = 0; i < spi_devices_used; i++)
/* Disabling spi module */
spi_enable(&spi_devices[i], 0);
}
DECLARE_HOOK(HOOK_INIT, sspi_init, HOOK_PRIO_INIT_SPI);