hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// SPDX-License-Identifier: GPL-2.0
/*
 * SPI access driver for rockchip rk806
 *
 * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
 *
 * Author: Xu Shengfei <xsf@rock-chips.com>
 */
 
#include <linux/mfd/rk806.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
 
static const struct of_device_id rk806_spi_of_match_table[] = {
   { .compatible = "rockchip,rk806", },
   { }
};
MODULE_DEVICE_TABLE(of, rk806_spi_of_match_table);
 
static int rk806_spi_write(struct spi_device *spi,
              char addr,
              const char *data,
              size_t data_len)
{
   char write_cmd = RK806_CMD_WRITE | (data_len - 1);
   char addrh = RK806_REG_H;
   struct spi_message m;
   int buffer, ret = 0;
   struct spi_transfer write_cmd_packet = {
       .tx_buf    = &buffer,
       .len    = sizeof(buffer),
   };
 
   buffer = write_cmd | (addr << 8) | (addrh << 16) | (*data << 24);
 
   spi_message_init(&m);
   spi_message_add_tail(&write_cmd_packet, &m);
   ret = spi_sync(spi, &m);
   return ret;
}
 
static int rk806_spi_bus_write(void *context, const void *data, size_t count)
{
   struct device *dev = context;
   struct spi_device *spi = to_spi_device(dev);
   char buf[2];
 
   if (count < 2) {
       dev_err(&spi->dev, "regmap write err!\n");
       return -EINVAL;
   }
   memcpy(buf, data, 2);
 
   return rk806_spi_write(spi, buf[0], &buf[1], (count - 1));
}
 
static int rk806_spi_bus_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);
   char addr;
   char txbuf[3] = { 0 };
 
   if (reg_size != sizeof(char) || val_size < 1)
       return -EINVAL;
 
   /* Copy address to read from into first element of SPI buffer. */
   memcpy(&addr, reg, sizeof(char));
 
   txbuf[0] = RK806_CMD_READ | (val_size - 1);
   txbuf[1] = addr;
   txbuf[2] = RK806_REG_H;
 
   return spi_write_then_read(spi, txbuf, 3, val, val_size);
}
 
static const struct regmap_bus rk806_regmap_bus_spi = {
   .write = rk806_spi_bus_write,
   .read = rk806_spi_bus_read,
   .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
   .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
 
static int rk806_spi_probe(struct spi_device *spi)
{
   struct rk806 *rk806;
 
   rk806 = devm_kzalloc(&spi->dev, sizeof(*rk806), GFP_KERNEL);
   if (!rk806)
       return -ENOMEM;
 
   spi_set_drvdata(spi, rk806);
   rk806->dev = &spi->dev;
   rk806->irq = spi->irq;
 
   rk806->regmap = devm_regmap_init(&spi->dev,
                    &rk806_regmap_bus_spi,
                    &spi->dev,
                    &rk806_regmap_config_spi);
   if (IS_ERR(rk806->regmap)) {
       dev_err(rk806->dev, "Failed to initialize register map\n");
       return PTR_ERR(rk806->regmap);
   }
 
   return rk806_device_init(rk806);
}
 
static int rk806_spi_remove(struct spi_device *spi)
{
   struct rk806 *rk806 = spi_get_drvdata(spi);
 
   return rk806_device_exit(rk806);
}
 
static const struct spi_device_id rk806_spi_id_table[] = {
   { "rk806", 0 },
   { /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, rk806_spi_id_table);
 
static struct spi_driver rk806_spi_driver = {
   .driver        = {
       .name    = "rk806",
       .owner = THIS_MODULE,
       .of_match_table = rk806_spi_of_match_table,
   },
   .probe        = rk806_spi_probe,
   .remove        = rk806_spi_remove,
   .id_table    = rk806_spi_id_table,
};
module_spi_driver(rk806_spi_driver);
 
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_DESCRIPTION("RK806 SPI Interface Driver");
MODULE_LICENSE("GPL v2");