Commit | Line | Data |
---|---|---|
325bec71 JP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * SPI access driver for TI TPS6594/TPS6593/LP8764 PMICs | |
4 | * | |
5 | * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ | |
6 | */ | |
7 | ||
8 | #include <linux/crc8.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/mod_devicetable.h> | |
11 | #include <linux/of_device.h> | |
12 | #include <linux/regmap.h> | |
13 | #include <linux/spi/spi.h> | |
14 | ||
15 | #include <linux/mfd/tps6594.h> | |
16 | ||
17 | #define TPS6594_SPI_PAGE_SHIFT 5 | |
18 | #define TPS6594_SPI_READ_BIT BIT(4) | |
19 | ||
20 | static bool enable_crc; | |
21 | module_param(enable_crc, bool, 0444); | |
22 | MODULE_PARM_DESC(enable_crc, "Enable CRC feature for SPI interface"); | |
23 | ||
24 | DECLARE_CRC8_TABLE(tps6594_spi_crc_table); | |
25 | ||
26 | static int tps6594_spi_reg_read(void *context, unsigned int reg, unsigned int *val) | |
27 | { | |
28 | struct spi_device *spi = context; | |
29 | struct tps6594 *tps = spi_get_drvdata(spi); | |
30 | u8 buf[4] = { 0 }; | |
31 | size_t count_rx = 1; | |
32 | int ret; | |
33 | ||
34 | buf[0] = reg; | |
35 | buf[1] = TPS6594_REG_TO_PAGE(reg) << TPS6594_SPI_PAGE_SHIFT | TPS6594_SPI_READ_BIT; | |
36 | ||
37 | if (tps->use_crc) | |
38 | count_rx++; | |
39 | ||
40 | ret = spi_write_then_read(spi, buf, 2, buf + 2, count_rx); | |
41 | if (ret < 0) | |
42 | return ret; | |
43 | ||
44 | if (tps->use_crc && buf[3] != crc8(tps6594_spi_crc_table, buf, 3, CRC8_INIT_VALUE)) | |
45 | return -EIO; | |
46 | ||
47 | *val = buf[2]; | |
48 | ||
49 | return 0; | |
50 | } | |
51 | ||
52 | static int tps6594_spi_reg_write(void *context, unsigned int reg, unsigned int val) | |
53 | { | |
54 | struct spi_device *spi = context; | |
55 | struct tps6594 *tps = spi_get_drvdata(spi); | |
56 | u8 buf[4] = { 0 }; | |
57 | size_t count = 3; | |
58 | ||
59 | buf[0] = reg; | |
60 | buf[1] = TPS6594_REG_TO_PAGE(reg) << TPS6594_SPI_PAGE_SHIFT; | |
61 | buf[2] = val; | |
62 | ||
63 | if (tps->use_crc) | |
64 | buf[3] = crc8(tps6594_spi_crc_table, buf, count++, CRC8_INIT_VALUE); | |
65 | ||
66 | return spi_write(spi, buf, count); | |
67 | } | |
68 | ||
69 | static const struct regmap_config tps6594_spi_regmap_config = { | |
70 | .reg_bits = 16, | |
71 | .val_bits = 8, | |
72 | .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, | |
73 | .volatile_reg = tps6594_is_volatile_reg, | |
74 | .reg_read = tps6594_spi_reg_read, | |
75 | .reg_write = tps6594_spi_reg_write, | |
76 | .use_single_read = true, | |
77 | .use_single_write = true, | |
78 | }; | |
79 | ||
80 | static const struct of_device_id tps6594_spi_of_match_table[] = { | |
81 | { .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, }, | |
82 | { .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, }, | |
83 | { .compatible = "ti,lp8764-q1", .data = (void *)LP8764, }, | |
84 | {} | |
85 | }; | |
86 | MODULE_DEVICE_TABLE(of, tps6594_spi_of_match_table); | |
87 | ||
88 | static int tps6594_spi_probe(struct spi_device *spi) | |
89 | { | |
90 | struct device *dev = &spi->dev; | |
91 | struct tps6594 *tps; | |
92 | const struct of_device_id *match; | |
93 | ||
94 | tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL); | |
95 | if (!tps) | |
96 | return -ENOMEM; | |
97 | ||
98 | spi_set_drvdata(spi, tps); | |
99 | ||
100 | tps->dev = dev; | |
4ae08845 | 101 | tps->reg = spi_get_chipselect(spi, 0); |
325bec71 JP |
102 | tps->irq = spi->irq; |
103 | ||
104 | tps->regmap = devm_regmap_init(dev, NULL, spi, &tps6594_spi_regmap_config); | |
105 | if (IS_ERR(tps->regmap)) | |
106 | return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); | |
107 | ||
108 | match = of_match_device(tps6594_spi_of_match_table, dev); | |
109 | if (!match) | |
cc5f2eb7 | 110 | return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); |
325bec71 JP |
111 | tps->chip_id = (unsigned long)match->data; |
112 | ||
113 | crc8_populate_msb(tps6594_spi_crc_table, TPS6594_CRC8_POLYNOMIAL); | |
114 | ||
115 | return tps6594_device_init(tps, enable_crc); | |
116 | } | |
117 | ||
118 | static struct spi_driver tps6594_spi_driver = { | |
119 | .driver = { | |
120 | .name = "tps6594", | |
121 | .of_match_table = tps6594_spi_of_match_table, | |
122 | }, | |
123 | .probe = tps6594_spi_probe, | |
124 | }; | |
125 | module_spi_driver(tps6594_spi_driver); | |
126 | ||
127 | MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>"); | |
128 | MODULE_DESCRIPTION("TPS6594 SPI Interface Driver"); | |
129 | MODULE_LICENSE("GPL"); |