| /* 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 mutex_t 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); |