1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Maxim Integrated MAX5432-MAX5435 digital potentiometer driver |
4 | * Copyright (C) 2019 Martin Kaiser <martin@kaiser.cx> |
5 | * |
6 | * Datasheet: |
7 | * https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf |
8 | */ |
9 | |
10 | #include <linux/i2c.h> |
11 | #include <linux/iio/iio.h> |
12 | #include <linux/limits.h> |
13 | #include <linux/module.h> |
14 | #include <linux/mod_devicetable.h> |
15 | #include <linux/property.h> |
16 | |
17 | /* All chip variants have 32 wiper positions. */ |
18 | #define MAX5432_MAX_POS 31 |
19 | |
20 | #define MAX5432_OHM_50K (50 * 1000) |
21 | #define MAX5432_OHM_100K (100 * 1000) |
22 | |
23 | /* Update the volatile (currently active) setting. */ |
24 | #define MAX5432_CMD_VREG 0x11 |
25 | |
26 | struct max5432_data { |
27 | struct i2c_client *client; |
28 | unsigned long ohm; |
29 | }; |
30 | |
31 | static const struct iio_chan_spec max5432_channels[] = { |
32 | { |
33 | .type = IIO_RESISTANCE, |
34 | .indexed = 1, |
35 | .output = 1, |
36 | .channel = 0, |
37 | .address = MAX5432_CMD_VREG, |
38 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
39 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
40 | } |
41 | }; |
42 | |
43 | static int max5432_read_raw(struct iio_dev *indio_dev, |
44 | struct iio_chan_spec const *chan, |
45 | int *val, int *val2, long mask) |
46 | { |
47 | struct max5432_data *data = iio_priv(indio_dev); |
48 | |
49 | if (mask != IIO_CHAN_INFO_SCALE) |
50 | return -EINVAL; |
51 | |
52 | if (unlikely(data->ohm > INT_MAX)) |
53 | return -ERANGE; |
54 | |
55 | *val = data->ohm; |
56 | *val2 = MAX5432_MAX_POS; |
57 | |
58 | return IIO_VAL_FRACTIONAL; |
59 | } |
60 | |
61 | static int max5432_write_raw(struct iio_dev *indio_dev, |
62 | struct iio_chan_spec const *chan, |
63 | int val, int val2, long mask) |
64 | { |
65 | struct max5432_data *data = iio_priv(indio_dev); |
66 | u8 data_byte; |
67 | |
68 | if (mask != IIO_CHAN_INFO_RAW) |
69 | return -EINVAL; |
70 | |
71 | if (val < 0 || val > MAX5432_MAX_POS) |
72 | return -EINVAL; |
73 | |
74 | if (val2 != 0) |
75 | return -EINVAL; |
76 | |
77 | /* Wiper position is in bits D7-D3. (D2-D0 are don't care bits.) */ |
78 | data_byte = val << 3; |
79 | return i2c_smbus_write_byte_data(client: data->client, command: chan->address, |
80 | value: data_byte); |
81 | } |
82 | |
83 | static const struct iio_info max5432_info = { |
84 | .read_raw = max5432_read_raw, |
85 | .write_raw = max5432_write_raw, |
86 | }; |
87 | |
88 | static int max5432_probe(struct i2c_client *client) |
89 | { |
90 | struct device *dev = &client->dev; |
91 | struct iio_dev *indio_dev; |
92 | struct max5432_data *data; |
93 | |
94 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(struct max5432_data)); |
95 | if (!indio_dev) |
96 | return -ENOMEM; |
97 | |
98 | i2c_set_clientdata(client, data: indio_dev); |
99 | |
100 | data = iio_priv(indio_dev); |
101 | data->client = client; |
102 | data->ohm = (unsigned long)device_get_match_data(dev); |
103 | |
104 | indio_dev->info = &max5432_info; |
105 | indio_dev->channels = max5432_channels; |
106 | indio_dev->num_channels = ARRAY_SIZE(max5432_channels); |
107 | indio_dev->name = client->name; |
108 | |
109 | return devm_iio_device_register(dev, indio_dev); |
110 | } |
111 | |
112 | static const struct of_device_id max5432_dt_ids[] = { |
113 | { .compatible = "maxim,max5432" , .data = (void *)MAX5432_OHM_50K }, |
114 | { .compatible = "maxim,max5433" , .data = (void *)MAX5432_OHM_100K }, |
115 | { .compatible = "maxim,max5434" , .data = (void *)MAX5432_OHM_50K }, |
116 | { .compatible = "maxim,max5435" , .data = (void *)MAX5432_OHM_100K }, |
117 | { /* sentinel */ } |
118 | }; |
119 | MODULE_DEVICE_TABLE(of, max5432_dt_ids); |
120 | |
121 | static struct i2c_driver max5432_driver = { |
122 | .driver = { |
123 | .name = "max5432" , |
124 | .of_match_table = max5432_dt_ids, |
125 | }, |
126 | .probe = max5432_probe, |
127 | }; |
128 | |
129 | module_i2c_driver(max5432_driver); |
130 | |
131 | MODULE_AUTHOR("Martin Kaiser <martin@kaiser.cx>" ); |
132 | MODULE_DESCRIPTION("max5432-max5435 digital potentiometers" ); |
133 | MODULE_LICENSE("GPL v2" ); |
134 | |