1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AD5593R Digital <-> Analog converters driver |
4 | * |
5 | * Copyright 2015-2016 Analog Devices Inc. |
6 | * Author: Paul Cercueil <paul.cercueil@analog.com> |
7 | */ |
8 | |
9 | #include "ad5592r-base.h" |
10 | |
11 | #include <linux/bitops.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/module.h> |
14 | #include <linux/mod_devicetable.h> |
15 | |
16 | #include <asm/unaligned.h> |
17 | |
18 | #define AD5593R_MODE_CONF (0 << 4) |
19 | #define AD5593R_MODE_DAC_WRITE (1 << 4) |
20 | #define AD5593R_MODE_ADC_READBACK (4 << 4) |
21 | #define AD5593R_MODE_DAC_READBACK (5 << 4) |
22 | #define AD5593R_MODE_GPIO_READBACK (6 << 4) |
23 | #define AD5593R_MODE_REG_READBACK (7 << 4) |
24 | |
25 | static int ad5593r_read_word(struct i2c_client *i2c, u8 reg, u16 *value) |
26 | { |
27 | int ret; |
28 | u8 buf[2]; |
29 | |
30 | ret = i2c_smbus_write_byte(client: i2c, value: reg); |
31 | if (ret < 0) |
32 | return ret; |
33 | |
34 | ret = i2c_master_recv(client: i2c, buf, count: sizeof(buf)); |
35 | if (ret < 0) |
36 | return ret; |
37 | |
38 | *value = get_unaligned_be16(p: buf); |
39 | |
40 | return 0; |
41 | } |
42 | |
43 | static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value) |
44 | { |
45 | struct i2c_client *i2c = to_i2c_client(st->dev); |
46 | |
47 | return i2c_smbus_write_word_swapped(client: i2c, |
48 | AD5593R_MODE_DAC_WRITE | chan, value); |
49 | } |
50 | |
51 | static int ad5593r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value) |
52 | { |
53 | struct i2c_client *i2c = to_i2c_client(st->dev); |
54 | s32 val; |
55 | |
56 | val = i2c_smbus_write_word_swapped(client: i2c, |
57 | AD5593R_MODE_CONF | AD5592R_REG_ADC_SEQ, BIT(chan)); |
58 | if (val < 0) |
59 | return (int) val; |
60 | |
61 | return ad5593r_read_word(i2c, AD5593R_MODE_ADC_READBACK, value); |
62 | } |
63 | |
64 | static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value) |
65 | { |
66 | struct i2c_client *i2c = to_i2c_client(st->dev); |
67 | |
68 | return i2c_smbus_write_word_swapped(client: i2c, |
69 | AD5593R_MODE_CONF | reg, value); |
70 | } |
71 | |
72 | static int ad5593r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value) |
73 | { |
74 | struct i2c_client *i2c = to_i2c_client(st->dev); |
75 | |
76 | return ad5593r_read_word(i2c, AD5593R_MODE_REG_READBACK | reg, value); |
77 | } |
78 | |
79 | static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value) |
80 | { |
81 | struct i2c_client *i2c = to_i2c_client(st->dev); |
82 | u16 val; |
83 | int ret; |
84 | |
85 | ret = ad5593r_read_word(i2c, AD5593R_MODE_GPIO_READBACK, value: &val); |
86 | if (ret) |
87 | return ret; |
88 | |
89 | *value = (u8) val; |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | static const struct ad5592r_rw_ops ad5593r_rw_ops = { |
95 | .write_dac = ad5593r_write_dac, |
96 | .read_adc = ad5593r_read_adc, |
97 | .reg_write = ad5593r_reg_write, |
98 | .reg_read = ad5593r_reg_read, |
99 | .gpio_read = ad5593r_gpio_read, |
100 | }; |
101 | |
102 | static int ad5593r_i2c_probe(struct i2c_client *i2c) |
103 | { |
104 | const struct i2c_device_id *id = i2c_client_get_device_id(client: i2c); |
105 | if (!i2c_check_functionality(adap: i2c->adapter, |
106 | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) |
107 | return -EOPNOTSUPP; |
108 | |
109 | return ad5592r_probe(dev: &i2c->dev, name: id->name, ops: &ad5593r_rw_ops); |
110 | } |
111 | |
112 | static void ad5593r_i2c_remove(struct i2c_client *i2c) |
113 | { |
114 | ad5592r_remove(dev: &i2c->dev); |
115 | } |
116 | |
117 | static const struct i2c_device_id ad5593r_i2c_ids[] = { |
118 | { .name = "ad5593r" , }, |
119 | {}, |
120 | }; |
121 | MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids); |
122 | |
123 | static const struct of_device_id ad5593r_of_match[] = { |
124 | { .compatible = "adi,ad5593r" , }, |
125 | {}, |
126 | }; |
127 | MODULE_DEVICE_TABLE(of, ad5593r_of_match); |
128 | |
129 | static const struct acpi_device_id ad5593r_acpi_match[] = { |
130 | {"ADS5593" , }, |
131 | { }, |
132 | }; |
133 | MODULE_DEVICE_TABLE(acpi, ad5593r_acpi_match); |
134 | |
135 | static struct i2c_driver ad5593r_driver = { |
136 | .driver = { |
137 | .name = "ad5593r" , |
138 | .of_match_table = ad5593r_of_match, |
139 | .acpi_match_table = ad5593r_acpi_match, |
140 | }, |
141 | .probe = ad5593r_i2c_probe, |
142 | .remove = ad5593r_i2c_remove, |
143 | .id_table = ad5593r_i2c_ids, |
144 | }; |
145 | module_i2c_driver(ad5593r_driver); |
146 | |
147 | MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>" ); |
148 | MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters" ); |
149 | MODULE_LICENSE("GPL v2" ); |
150 | MODULE_IMPORT_NS(IIO_AD5592R); |
151 | |