1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ADGS1408/ADGS1409 SPI MUX driver |
4 | * |
5 | * Copyright 2018 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/err.h> |
9 | #include <linux/mod_devicetable.h> |
10 | #include <linux/module.h> |
11 | #include <linux/mux/driver.h> |
12 | #include <linux/property.h> |
13 | #include <linux/spi/spi.h> |
14 | |
15 | #define ADGS1408_SW_DATA (0x01) |
16 | #define ADGS1408_REG_READ(reg) ((reg) | 0x80) |
17 | #define ADGS1408_DISABLE (0x00) |
18 | #define ADGS1408_MUX(state) (((state) << 1) | 1) |
19 | |
20 | enum adgs1408_chip_id { |
21 | ADGS1408 = 1, |
22 | ADGS1409, |
23 | }; |
24 | |
25 | static int adgs1408_spi_reg_write(struct spi_device *spi, |
26 | u8 reg_addr, u8 reg_data) |
27 | { |
28 | u8 tx_buf[2]; |
29 | |
30 | tx_buf[0] = reg_addr; |
31 | tx_buf[1] = reg_data; |
32 | |
33 | return spi_write_then_read(spi, txbuf: tx_buf, n_tx: sizeof(tx_buf), NULL, n_rx: 0); |
34 | } |
35 | |
36 | static int adgs1408_set(struct mux_control *mux, int state) |
37 | { |
38 | struct spi_device *spi = to_spi_device(dev: mux->chip->dev.parent); |
39 | u8 reg; |
40 | |
41 | if (state == MUX_IDLE_DISCONNECT) |
42 | reg = ADGS1408_DISABLE; |
43 | else |
44 | reg = ADGS1408_MUX(state); |
45 | |
46 | return adgs1408_spi_reg_write(spi, ADGS1408_SW_DATA, reg_data: reg); |
47 | } |
48 | |
49 | static const struct mux_control_ops adgs1408_ops = { |
50 | .set = adgs1408_set, |
51 | }; |
52 | |
53 | static int adgs1408_probe(struct spi_device *spi) |
54 | { |
55 | struct device *dev = &spi->dev; |
56 | enum adgs1408_chip_id chip_id; |
57 | struct mux_chip *mux_chip; |
58 | struct mux_control *mux; |
59 | s32 idle_state; |
60 | int ret; |
61 | |
62 | chip_id = (enum adgs1408_chip_id)device_get_match_data(dev); |
63 | if (!chip_id) |
64 | chip_id = spi_get_device_id(sdev: spi)->driver_data; |
65 | |
66 | mux_chip = devm_mux_chip_alloc(dev, controllers: 1, sizeof_priv: 0); |
67 | if (IS_ERR(ptr: mux_chip)) |
68 | return PTR_ERR(ptr: mux_chip); |
69 | |
70 | mux_chip->ops = &adgs1408_ops; |
71 | |
72 | ret = adgs1408_spi_reg_write(spi, ADGS1408_SW_DATA, ADGS1408_DISABLE); |
73 | if (ret < 0) |
74 | return ret; |
75 | |
76 | ret = device_property_read_u32(dev, propname: "idle-state" , val: (u32 *)&idle_state); |
77 | if (ret < 0) |
78 | idle_state = MUX_IDLE_AS_IS; |
79 | |
80 | mux = mux_chip->mux; |
81 | |
82 | if (chip_id == ADGS1408) |
83 | mux->states = 8; |
84 | else |
85 | mux->states = 4; |
86 | |
87 | switch (idle_state) { |
88 | case MUX_IDLE_DISCONNECT: |
89 | case MUX_IDLE_AS_IS: |
90 | case 0 ... 7: |
91 | /* adgs1409 supports only 4 states */ |
92 | if (idle_state < mux->states) { |
93 | mux->idle_state = idle_state; |
94 | break; |
95 | } |
96 | fallthrough; |
97 | default: |
98 | dev_err(dev, "invalid idle-state %d\n" , idle_state); |
99 | return -EINVAL; |
100 | } |
101 | |
102 | return devm_mux_chip_register(dev, mux_chip); |
103 | } |
104 | |
105 | static const struct spi_device_id adgs1408_spi_id[] = { |
106 | { "adgs1408" , ADGS1408 }, |
107 | { "adgs1409" , ADGS1409 }, |
108 | { } |
109 | }; |
110 | MODULE_DEVICE_TABLE(spi, adgs1408_spi_id); |
111 | |
112 | static const struct of_device_id adgs1408_of_match[] = { |
113 | { .compatible = "adi,adgs1408" , .data = (void *)ADGS1408, }, |
114 | { .compatible = "adi,adgs1409" , .data = (void *)ADGS1409, }, |
115 | { } |
116 | }; |
117 | MODULE_DEVICE_TABLE(of, adgs1408_of_match); |
118 | |
119 | static struct spi_driver adgs1408_driver = { |
120 | .driver = { |
121 | .name = "adgs1408" , |
122 | .of_match_table = adgs1408_of_match, |
123 | }, |
124 | .probe = adgs1408_probe, |
125 | .id_table = adgs1408_spi_id, |
126 | }; |
127 | module_spi_driver(adgs1408_driver); |
128 | |
129 | MODULE_AUTHOR("Mircea Caprioru <mircea.caprioru@analog.com>" ); |
130 | MODULE_DESCRIPTION("Analog Devices ADGS1408 MUX driver" ); |
131 | MODULE_LICENSE("GPL" ); |
132 | |