blob: d7c4ab64f158ab364b2089d905bf3b4669672297 [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include <fdtdec.h>
void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
unsigned int cs)
{
struct spi_slave *slave;
void *ptr;
ptr = malloc(size);
if (ptr) {
memset(ptr, '\0', size);
slave = (struct spi_slave *)(ptr + offset);
slave->bus = bus;
slave->cs = cs;
}
return ptr;
}
#ifdef CONFIG_OF_SPI
/**
* Set up a new SPI slave for an fdt node
*
* @param blob Device tree blob
* @param slave_node pointer to this SPI slave node in the device tree
* @param spi_node cached pointer to the SPI interface this node belongs to
* @return pointer to a new slave if ok, NULL on error
*/
struct spi_slave *spi_setup_slave_fdt(const void *blob,
int slave_node,
int spi_node)
{
unsigned int bus_index;
uint32_t max_freq;
unsigned cs;
unsigned mode = 0;
int half_duplex;
struct spi_slave *spi_slave;
unsigned frame_header = 0;
bus_index = spi_get_bus_by_node(blob, spi_node);
if (bus_index < 0) {
debug("%s: Failed to find bus node %d\n", __func__, spi_node);
return NULL;
}
/* Decode slave-specific params, providing sendible defaults */
max_freq = fdtdec_get_int(blob, slave_node,
"spi-max-frequency", 0);
if (fdtdec_get_bool(blob, slave_node, "spi-cpol"))
mode |= SPI_CPOL;
if (fdtdec_get_bool(blob, slave_node, "spi-cpha"))
mode |= SPI_CPHA;
if (fdtdec_get_bool(blob, slave_node, "spi-cs-high"))
mode |= SPI_CS_HIGH;
cs = fdtdec_get_int(blob, slave_node, "reg", 0);
half_duplex = fdtdec_get_bool(blob, slave_node, "spi-half-duplex");
if (half_duplex) {
frame_header = fdtdec_get_int(blob, slave_node,
"spi-frame-header", 0x100);
if (frame_header >= 0x100) {
debug("%s: frame header not defined or invalid!\n",
__func__);
return NULL;
}
}
spi_slave = spi_setup_slave(bus_index, cs, max_freq, mode);
if (spi_slave && half_duplex) {
spi_slave->half_duplex = 1;
spi_slave->frame_header = frame_header;
spi_slave->max_timeout_ms = fdtdec_get_int(blob,
slave_node,
"spi-max-timeout-ms",
1000);
}
return spi_slave;
}
#endif /* CONFIG_OF_SPI */