18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Register map access API - SPI support
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright 2011 Wolfson Microelectronics plc
68c2ecf20Sopenharmony_ci//
78c2ecf20Sopenharmony_ci// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/regmap.h>
108c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "internal.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistruct regmap_async_spi {
168c2ecf20Sopenharmony_ci	struct regmap_async core;
178c2ecf20Sopenharmony_ci	struct spi_message m;
188c2ecf20Sopenharmony_ci	struct spi_transfer t[2];
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void regmap_spi_complete(void *data)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct regmap_async_spi *async = data;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	regmap_async_complete_cb(&async->core, async->m.status);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int regmap_spi_write(void *context, const void *data, size_t count)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct device *dev = context;
318c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	return spi_write(spi, data, count);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int regmap_spi_gather_write(void *context,
378c2ecf20Sopenharmony_ci				   const void *reg, size_t reg_len,
388c2ecf20Sopenharmony_ci				   const void *val, size_t val_len)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct device *dev = context;
418c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
428c2ecf20Sopenharmony_ci	struct spi_message m;
438c2ecf20Sopenharmony_ci	struct spi_transfer t[2] = { { .tx_buf = reg, .len = reg_len, },
448c2ecf20Sopenharmony_ci				     { .tx_buf = val, .len = val_len, }, };
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	spi_message_init(&m);
478c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
488c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return spi_sync(spi, &m);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int regmap_spi_async_write(void *context,
548c2ecf20Sopenharmony_ci				  const void *reg, size_t reg_len,
558c2ecf20Sopenharmony_ci				  const void *val, size_t val_len,
568c2ecf20Sopenharmony_ci				  struct regmap_async *a)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct regmap_async_spi *async = container_of(a,
598c2ecf20Sopenharmony_ci						      struct regmap_async_spi,
608c2ecf20Sopenharmony_ci						      core);
618c2ecf20Sopenharmony_ci	struct device *dev = context;
628c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	async->t[0].tx_buf = reg;
658c2ecf20Sopenharmony_ci	async->t[0].len = reg_len;
668c2ecf20Sopenharmony_ci	async->t[1].tx_buf = val;
678c2ecf20Sopenharmony_ci	async->t[1].len = val_len;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	spi_message_init(&async->m);
708c2ecf20Sopenharmony_ci	spi_message_add_tail(&async->t[0], &async->m);
718c2ecf20Sopenharmony_ci	if (val)
728c2ecf20Sopenharmony_ci		spi_message_add_tail(&async->t[1], &async->m);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	async->m.complete = regmap_spi_complete;
758c2ecf20Sopenharmony_ci	async->m.context = async;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return spi_async(spi, &async->m);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic struct regmap_async *regmap_spi_async_alloc(void)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct regmap_async_spi *async_spi;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL);
858c2ecf20Sopenharmony_ci	if (!async_spi)
868c2ecf20Sopenharmony_ci		return NULL;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return &async_spi->core;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int regmap_spi_read(void *context,
928c2ecf20Sopenharmony_ci			   const void *reg, size_t reg_size,
938c2ecf20Sopenharmony_ci			   void *val, size_t val_size)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct device *dev = context;
968c2ecf20Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return spi_write_then_read(spi, reg, reg_size, val, val_size);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct regmap_bus regmap_spi = {
1028c2ecf20Sopenharmony_ci	.write = regmap_spi_write,
1038c2ecf20Sopenharmony_ci	.gather_write = regmap_spi_gather_write,
1048c2ecf20Sopenharmony_ci	.async_write = regmap_spi_async_write,
1058c2ecf20Sopenharmony_ci	.async_alloc = regmap_spi_async_alloc,
1068c2ecf20Sopenharmony_ci	.read = regmap_spi_read,
1078c2ecf20Sopenharmony_ci	.read_flag_mask = 0x80,
1088c2ecf20Sopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
1098c2ecf20Sopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_BIG,
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistruct regmap *__regmap_init_spi(struct spi_device *spi,
1138c2ecf20Sopenharmony_ci				 const struct regmap_config *config,
1148c2ecf20Sopenharmony_ci				 struct lock_class_key *lock_key,
1158c2ecf20Sopenharmony_ci				 const char *lock_name)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	return __regmap_init(&spi->dev, &regmap_spi, &spi->dev, config,
1188c2ecf20Sopenharmony_ci			     lock_key, lock_name);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__regmap_init_spi);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistruct regmap *__devm_regmap_init_spi(struct spi_device *spi,
1238c2ecf20Sopenharmony_ci				      const struct regmap_config *config,
1248c2ecf20Sopenharmony_ci				      struct lock_class_key *lock_key,
1258c2ecf20Sopenharmony_ci				      const char *lock_name)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	return __devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config,
1288c2ecf20Sopenharmony_ci				  lock_key, lock_name);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__devm_regmap_init_spi);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
133