125 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Rockchip RK806 Core (SPI) driver4 *5 * Copyright (c) 2021 Rockchip Electronics Co., Ltd.6 * Copyright (c) 2023 Collabora Ltd.7 *8 * Author: Xu Shengfei <xsf@rock-chips.com>9 * Author: Sebastian Reichel <sebastian.reichel@collabora.com>10 */11 12#include <linux/interrupt.h>13#include <linux/mfd/core.h>14#include <linux/mfd/rk808.h>15#include <linux/module.h>16#include <linux/regmap.h>17#include <linux/spi/spi.h>18 19#define RK806_ADDR_SIZE 220#define RK806_CMD_WITH_SIZE(CMD, VALUE_BYTES) \21 (RK806_CMD_##CMD | RK806_CMD_CRC_DIS | (VALUE_BYTES - 1))22 23static const struct regmap_range rk806_volatile_ranges[] = {24 regmap_reg_range(RK806_POWER_EN0, RK806_POWER_EN5),25 regmap_reg_range(RK806_DVS_START_CTRL, RK806_INT_MSK1),26};27 28static const struct regmap_access_table rk806_volatile_table = {29 .yes_ranges = rk806_volatile_ranges,30 .n_yes_ranges = ARRAY_SIZE(rk806_volatile_ranges),31};32 33static const struct regmap_config rk806_regmap_config_spi = {34 .reg_bits = 16,35 .val_bits = 8,36 .max_register = RK806_BUCK_RSERVE_REG5,37 .cache_type = REGCACHE_MAPLE,38 .volatile_table = &rk806_volatile_table,39};40 41static int rk806_spi_bus_write(void *context, const void *vdata, size_t count)42{43 struct device *dev = context;44 struct spi_device *spi = to_spi_device(dev);45 struct spi_transfer xfer[2] = { 0 };46 /* data and thus count includes the register address */47 size_t val_size = count - RK806_ADDR_SIZE;48 char cmd;49 50 if (val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))51 return -EINVAL;52 53 cmd = RK806_CMD_WITH_SIZE(WRITE, val_size);54 55 xfer[0].tx_buf = &cmd;56 xfer[0].len = sizeof(cmd);57 xfer[1].tx_buf = vdata;58 xfer[1].len = count;59 60 return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));61}62 63static int rk806_spi_bus_read(void *context, const void *vreg, size_t reg_size,64 void *val, size_t val_size)65{66 struct device *dev = context;67 struct spi_device *spi = to_spi_device(dev);68 char txbuf[3] = { 0 };69 70 if (reg_size != RK806_ADDR_SIZE ||71 val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))72 return -EINVAL;73 74 /* TX buffer contains command byte followed by two address bytes */75 txbuf[0] = RK806_CMD_WITH_SIZE(READ, val_size);76 memcpy(txbuf+1, vreg, reg_size);77 78 return spi_write_then_read(spi, txbuf, sizeof(txbuf), val, val_size);79}80 81static const struct regmap_bus rk806_regmap_bus_spi = {82 .write = rk806_spi_bus_write,83 .read = rk806_spi_bus_read,84 .reg_format_endian_default = REGMAP_ENDIAN_LITTLE,85};86 87static int rk8xx_spi_probe(struct spi_device *spi)88{89 struct regmap *regmap;90 91 regmap = devm_regmap_init(&spi->dev, &rk806_regmap_bus_spi,92 &spi->dev, &rk806_regmap_config_spi);93 if (IS_ERR(regmap))94 return dev_err_probe(&spi->dev, PTR_ERR(regmap),95 "Failed to init regmap\n");96 97 return rk8xx_probe(&spi->dev, RK806_ID, spi->irq, regmap);98}99 100static const struct of_device_id rk8xx_spi_of_match[] = {101 { .compatible = "rockchip,rk806", },102 { }103};104MODULE_DEVICE_TABLE(of, rk8xx_spi_of_match);105 106static const struct spi_device_id rk8xx_spi_id_table[] = {107 { "rk806", 0 },108 { }109};110MODULE_DEVICE_TABLE(spi, rk8xx_spi_id_table);111 112static struct spi_driver rk8xx_spi_driver = {113 .driver = {114 .name = "rk8xx-spi",115 .of_match_table = rk8xx_spi_of_match,116 },117 .probe = rk8xx_spi_probe,118 .id_table = rk8xx_spi_id_table,119};120module_spi_driver(rk8xx_spi_driver);121 122MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");123MODULE_DESCRIPTION("RK8xx SPI PMIC driver");124MODULE_LICENSE("GPL");125