mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
d647c19951
For many drivers which will support rich endianness of Devices need define DT properties by itself with the binding support. The endianness using regmap: Index Device Properties if needs bytes-swap, or just ignore it ------------------------------------------------------------- 1 BE 'big-endian' 2 LE 'little-endian' The properties include all the register values and the buffers. And these properties are very usful for the MMIO devices: Such as: a memory-mapped device, on one SoC is in BE mode, while in another SoC will be in LE mode, and the CPU will always in LE mode. For the first case, we must use cpu_to_be32/be32_to_cpu for 32-bit registers accessing, so the 'big-endian' property is needed. For the second case, we can just ignore the bytes-swap functions like cpu_to_le32/le32_to_cpu, so the 'little-endian' property could be abscent. And vice versa... Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
150 lines
3.8 KiB
C
150 lines
3.8 KiB
C
/*
|
|
* Register map access API - SPI support
|
|
*
|
|
* Copyright 2011 Wolfson Microelectronics plc
|
|
*
|
|
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/regmap.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/module.h>
|
|
|
|
#include "internal.h"
|
|
|
|
struct regmap_async_spi {
|
|
struct regmap_async core;
|
|
struct spi_message m;
|
|
struct spi_transfer t[2];
|
|
};
|
|
|
|
static void regmap_spi_complete(void *data)
|
|
{
|
|
struct regmap_async_spi *async = data;
|
|
|
|
regmap_async_complete_cb(&async->core, async->m.status);
|
|
}
|
|
|
|
static int regmap_spi_write(void *context, const void *data, size_t count)
|
|
{
|
|
struct device *dev = context;
|
|
struct spi_device *spi = to_spi_device(dev);
|
|
|
|
return spi_write(spi, data, count);
|
|
}
|
|
|
|
static int regmap_spi_gather_write(void *context,
|
|
const void *reg, size_t reg_len,
|
|
const void *val, size_t val_len)
|
|
{
|
|
struct device *dev = context;
|
|
struct spi_device *spi = to_spi_device(dev);
|
|
struct spi_message m;
|
|
struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
|
|
{ .tx_buf = val, .len = val_len, }, };
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t[0], &m);
|
|
spi_message_add_tail(&t[1], &m);
|
|
|
|
return spi_sync(spi, &m);
|
|
}
|
|
|
|
static int regmap_spi_async_write(void *context,
|
|
const void *reg, size_t reg_len,
|
|
const void *val, size_t val_len,
|
|
struct regmap_async *a)
|
|
{
|
|
struct regmap_async_spi *async = container_of(a,
|
|
struct regmap_async_spi,
|
|
core);
|
|
struct device *dev = context;
|
|
struct spi_device *spi = to_spi_device(dev);
|
|
|
|
async->t[0].tx_buf = reg;
|
|
async->t[0].len = reg_len;
|
|
async->t[1].tx_buf = val;
|
|
async->t[1].len = val_len;
|
|
|
|
spi_message_init(&async->m);
|
|
spi_message_add_tail(&async->t[0], &async->m);
|
|
if (val)
|
|
spi_message_add_tail(&async->t[1], &async->m);
|
|
|
|
async->m.complete = regmap_spi_complete;
|
|
async->m.context = async;
|
|
|
|
return spi_async(spi, &async->m);
|
|
}
|
|
|
|
static struct regmap_async *regmap_spi_async_alloc(void)
|
|
{
|
|
struct regmap_async_spi *async_spi;
|
|
|
|
async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL);
|
|
if (!async_spi)
|
|
return NULL;
|
|
|
|
return &async_spi->core;
|
|
}
|
|
|
|
static int regmap_spi_read(void *context,
|
|
const void *reg, size_t reg_size,
|
|
void *val, size_t val_size)
|
|
{
|
|
struct device *dev = context;
|
|
struct spi_device *spi = to_spi_device(dev);
|
|
|
|
return spi_write_then_read(spi, reg, reg_size, val, val_size);
|
|
}
|
|
|
|
static struct regmap_bus regmap_spi = {
|
|
.write = regmap_spi_write,
|
|
.gather_write = regmap_spi_gather_write,
|
|
.async_write = regmap_spi_async_write,
|
|
.async_alloc = regmap_spi_async_alloc,
|
|
.read = regmap_spi_read,
|
|
.read_flag_mask = 0x80,
|
|
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
|
|
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
|
};
|
|
|
|
/**
|
|
* regmap_init_spi(): Initialise register map
|
|
*
|
|
* @spi: Device that will be interacted with
|
|
* @config: Configuration for register map
|
|
*
|
|
* The return value will be an ERR_PTR() on error or a valid pointer to
|
|
* a struct regmap.
|
|
*/
|
|
struct regmap *regmap_init_spi(struct spi_device *spi,
|
|
const struct regmap_config *config)
|
|
{
|
|
return regmap_init(&spi->dev, ®map_spi, &spi->dev, config);
|
|
}
|
|
EXPORT_SYMBOL_GPL(regmap_init_spi);
|
|
|
|
/**
|
|
* devm_regmap_init_spi(): Initialise register map
|
|
*
|
|
* @spi: Device that will be interacted with
|
|
* @config: Configuration for register map
|
|
*
|
|
* The return value will be an ERR_PTR() on error or a valid pointer
|
|
* to a struct regmap. The map will be automatically freed by the
|
|
* device management code.
|
|
*/
|
|
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
|
|
const struct regmap_config *config)
|
|
{
|
|
return devm_regmap_init(&spi->dev, ®map_spi, &spi->dev, config);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_regmap_init_spi);
|
|
|
|
MODULE_LICENSE("GPL");
|