13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * SPI access driver for rockchip rk806
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * Author: Xu Shengfei <xsf@rock-chips.com>
83d0407baSopenharmony_ci */
93d0407baSopenharmony_ci
103d0407baSopenharmony_ci#include <linux/mfd/rk806.h>
113d0407baSopenharmony_ci#include <linux/module.h>
123d0407baSopenharmony_ci#include <linux/regmap.h>
133d0407baSopenharmony_ci#include <linux/spi/spi.h>
143d0407baSopenharmony_ci
153d0407baSopenharmony_cistatic const struct of_device_id rk806_spi_of_match_table[] = {
163d0407baSopenharmony_ci	{ .compatible = "rockchip,rk806", },
173d0407baSopenharmony_ci	{ }
183d0407baSopenharmony_ci};
193d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, rk806_spi_of_match_table);
203d0407baSopenharmony_ci
213d0407baSopenharmony_cistatic int rk806_spi_write(struct spi_device *spi,
223d0407baSopenharmony_ci			   char addr,
233d0407baSopenharmony_ci			   const char *data,
243d0407baSopenharmony_ci			   size_t data_len)
253d0407baSopenharmony_ci{
263d0407baSopenharmony_ci	char write_cmd = RK806_CMD_WRITE | (data_len - 1);
273d0407baSopenharmony_ci	char addrh = RK806_REG_H;
283d0407baSopenharmony_ci	struct spi_message m;
293d0407baSopenharmony_ci	int buffer, ret = 0;
303d0407baSopenharmony_ci	struct spi_transfer write_cmd_packet = {
313d0407baSopenharmony_ci		.tx_buf	= &buffer,
323d0407baSopenharmony_ci		.len	= sizeof(buffer),
333d0407baSopenharmony_ci	};
343d0407baSopenharmony_ci
353d0407baSopenharmony_ci	buffer = write_cmd | (addr << 8) | (addrh << 16) | (*data << 24);
363d0407baSopenharmony_ci
373d0407baSopenharmony_ci	spi_message_init(&m);
383d0407baSopenharmony_ci	spi_message_add_tail(&write_cmd_packet, &m);
393d0407baSopenharmony_ci	ret = spi_sync(spi, &m);
403d0407baSopenharmony_ci	return ret;
413d0407baSopenharmony_ci}
423d0407baSopenharmony_ci
433d0407baSopenharmony_cistatic int rk806_spi_bus_write(void *context, const void *data, size_t count)
443d0407baSopenharmony_ci{
453d0407baSopenharmony_ci	struct device *dev = context;
463d0407baSopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
473d0407baSopenharmony_ci	char buf[2];
483d0407baSopenharmony_ci
493d0407baSopenharmony_ci	if (count < 2) {
503d0407baSopenharmony_ci		dev_err(&spi->dev, "regmap write err!\n");
513d0407baSopenharmony_ci		return -EINVAL;
523d0407baSopenharmony_ci	}
533d0407baSopenharmony_ci	memcpy(buf, data, 2);
543d0407baSopenharmony_ci
553d0407baSopenharmony_ci	return rk806_spi_write(spi, buf[0], &buf[1], (count - 1));
563d0407baSopenharmony_ci}
573d0407baSopenharmony_ci
583d0407baSopenharmony_cistatic int rk806_spi_bus_read(void *context,
593d0407baSopenharmony_ci			      const void *reg,
603d0407baSopenharmony_ci			      size_t reg_size,
613d0407baSopenharmony_ci			      void *val,
623d0407baSopenharmony_ci			      size_t val_size)
633d0407baSopenharmony_ci{
643d0407baSopenharmony_ci	struct device *dev = context;
653d0407baSopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
663d0407baSopenharmony_ci	char addr;
673d0407baSopenharmony_ci	char txbuf[3] = { 0 };
683d0407baSopenharmony_ci
693d0407baSopenharmony_ci	if (reg_size != sizeof(char) || val_size < 1)
703d0407baSopenharmony_ci		return -EINVAL;
713d0407baSopenharmony_ci
723d0407baSopenharmony_ci	/* Copy address to read from into first element of SPI buffer. */
733d0407baSopenharmony_ci	memcpy(&addr, reg, sizeof(char));
743d0407baSopenharmony_ci
753d0407baSopenharmony_ci	txbuf[0] = RK806_CMD_READ | (val_size - 1);
763d0407baSopenharmony_ci	txbuf[1] = addr;
773d0407baSopenharmony_ci	txbuf[2] = RK806_REG_H;
783d0407baSopenharmony_ci
793d0407baSopenharmony_ci	return spi_write_then_read(spi, txbuf, 3, val, val_size);
803d0407baSopenharmony_ci}
813d0407baSopenharmony_ci
823d0407baSopenharmony_cistatic const struct regmap_bus rk806_regmap_bus_spi = {
833d0407baSopenharmony_ci	.write = rk806_spi_bus_write,
843d0407baSopenharmony_ci	.read = rk806_spi_bus_read,
853d0407baSopenharmony_ci	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
863d0407baSopenharmony_ci	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
873d0407baSopenharmony_ci};
883d0407baSopenharmony_ci
893d0407baSopenharmony_cistatic int rk806_spi_probe(struct spi_device *spi)
903d0407baSopenharmony_ci{
913d0407baSopenharmony_ci	struct rk806 *rk806;
923d0407baSopenharmony_ci
933d0407baSopenharmony_ci	rk806 = devm_kzalloc(&spi->dev, sizeof(*rk806), GFP_KERNEL);
943d0407baSopenharmony_ci	if (!rk806)
953d0407baSopenharmony_ci		return -ENOMEM;
963d0407baSopenharmony_ci
973d0407baSopenharmony_ci	spi_set_drvdata(spi, rk806);
983d0407baSopenharmony_ci	rk806->dev = &spi->dev;
993d0407baSopenharmony_ci	rk806->irq = spi->irq;
1003d0407baSopenharmony_ci
1013d0407baSopenharmony_ci	rk806->regmap = devm_regmap_init(&spi->dev,
1023d0407baSopenharmony_ci					 &rk806_regmap_bus_spi,
1033d0407baSopenharmony_ci					 &spi->dev,
1043d0407baSopenharmony_ci					 &rk806_regmap_config_spi);
1053d0407baSopenharmony_ci	if (IS_ERR(rk806->regmap)) {
1063d0407baSopenharmony_ci		dev_err(rk806->dev, "Failed to initialize register map\n");
1073d0407baSopenharmony_ci		return PTR_ERR(rk806->regmap);
1083d0407baSopenharmony_ci	}
1093d0407baSopenharmony_ci
1103d0407baSopenharmony_ci	return rk806_device_init(rk806);
1113d0407baSopenharmony_ci}
1123d0407baSopenharmony_ci
1133d0407baSopenharmony_cistatic int rk806_spi_remove(struct spi_device *spi)
1143d0407baSopenharmony_ci{
1153d0407baSopenharmony_ci	struct rk806 *rk806 = spi_get_drvdata(spi);
1163d0407baSopenharmony_ci
1173d0407baSopenharmony_ci	return rk806_device_exit(rk806);
1183d0407baSopenharmony_ci}
1193d0407baSopenharmony_ci
1203d0407baSopenharmony_cistatic const struct spi_device_id rk806_spi_id_table[] = {
1213d0407baSopenharmony_ci	{ "rk806", 0 },
1223d0407baSopenharmony_ci	{ /* sentinel */ }
1233d0407baSopenharmony_ci};
1243d0407baSopenharmony_ciMODULE_DEVICE_TABLE(spi, rk806_spi_id_table);
1253d0407baSopenharmony_ci
1263d0407baSopenharmony_cistatic struct spi_driver rk806_spi_driver = {
1273d0407baSopenharmony_ci	.driver		= {
1283d0407baSopenharmony_ci		.name	= "rk806",
1293d0407baSopenharmony_ci		.owner = THIS_MODULE,
1303d0407baSopenharmony_ci		.of_match_table = rk806_spi_of_match_table,
1313d0407baSopenharmony_ci	},
1323d0407baSopenharmony_ci	.probe		= rk806_spi_probe,
1333d0407baSopenharmony_ci	.remove		= rk806_spi_remove,
1343d0407baSopenharmony_ci	.id_table	= rk806_spi_id_table,
1353d0407baSopenharmony_ci};
1363d0407baSopenharmony_cimodule_spi_driver(rk806_spi_driver);
1373d0407baSopenharmony_ci
1383d0407baSopenharmony_ciMODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
1393d0407baSopenharmony_ciMODULE_DESCRIPTION("RK806 SPI Interface Driver");
1403d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
141