Commit | Line | Data |
---|---|---|
8b9ce695 MC |
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/module.h> | |
10 | #include <linux/mux/driver.h> | |
11 | #include <linux/of_platform.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, tx_buf, sizeof(tx_buf), NULL, 0); | |
34 | } | |
35 | ||
36 | static int adgs1408_set(struct mux_control *mux, int state) | |
37 | { | |
38 | struct spi_device *spi = to_spi_device(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); | |
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)of_device_get_match_data(dev); | |
63 | if (!chip_id) | |
64 | chip_id = spi_get_device_id(spi)->driver_data; | |
65 | ||
66 | mux_chip = devm_mux_chip_alloc(dev, 1, 0); | |
67 | if (IS_ERR(mux_chip)) | |
68 | return PTR_ERR(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, "idle-state", (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 | /* fall through */ | |
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 = of_match_ptr(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"); | |
38a12607 | 131 | MODULE_LICENSE("GPL"); |