1*7b24a034SAndrea Collamati // SPDX-License-Identifier: GPL-2.0-only 2*7b24a034SAndrea Collamati /* 3*7b24a034SAndrea Collamati * Support for Microchip MCP4728 4*7b24a034SAndrea Collamati * 5*7b24a034SAndrea Collamati * Copyright (C) 2023 Andrea Collamati <andrea.collamati@gmail.com> 6*7b24a034SAndrea Collamati * 7*7b24a034SAndrea Collamati * Based on mcp4725 by Peter Meerwald <pmeerw@pmeerw.net> 8*7b24a034SAndrea Collamati * 9*7b24a034SAndrea Collamati * Driver for the Microchip I2C 12-bit digital-to-analog quad channels 10*7b24a034SAndrea Collamati * converter (DAC). 11*7b24a034SAndrea Collamati * 12*7b24a034SAndrea Collamati * (7-bit I2C slave address 0x60, the three LSBs can be configured in 13*7b24a034SAndrea Collamati * hardware) 14*7b24a034SAndrea Collamati */ 15*7b24a034SAndrea Collamati 16*7b24a034SAndrea Collamati #include <linux/bitfield.h> 17*7b24a034SAndrea Collamati #include <linux/delay.h> 18*7b24a034SAndrea Collamati #include <linux/err.h> 19*7b24a034SAndrea Collamati #include <linux/i2c.h> 20*7b24a034SAndrea Collamati #include <linux/iio/iio.h> 21*7b24a034SAndrea Collamati #include <linux/iio/sysfs.h> 22*7b24a034SAndrea Collamati #include <linux/module.h> 23*7b24a034SAndrea Collamati #include <linux/mod_devicetable.h> 24*7b24a034SAndrea Collamati #include <linux/property.h> 25*7b24a034SAndrea Collamati #include <linux/regulator/consumer.h> 26*7b24a034SAndrea Collamati 27*7b24a034SAndrea Collamati #define MCP4728_RESOLUTION 12 28*7b24a034SAndrea Collamati #define MCP4728_N_CHANNELS 4 29*7b24a034SAndrea Collamati 30*7b24a034SAndrea Collamati #define MCP4728_CMD_MASK GENMASK(7, 3) 31*7b24a034SAndrea Collamati #define MCP4728_CHSEL_MASK GENMASK(2, 1) 32*7b24a034SAndrea Collamati #define MCP4728_UDAC_MASK BIT(0) 33*7b24a034SAndrea Collamati 34*7b24a034SAndrea Collamati #define MCP4728_VREF_MASK BIT(7) 35*7b24a034SAndrea Collamati #define MCP4728_PDMODE_MASK GENMASK(6, 5) 36*7b24a034SAndrea Collamati #define MCP4728_GAIN_MASK BIT(4) 37*7b24a034SAndrea Collamati 38*7b24a034SAndrea Collamati #define MCP4728_DAC_H_MASK GENMASK(3, 0) 39*7b24a034SAndrea Collamati #define MCP4728_DAC_L_MASK GENMASK(7, 0) 40*7b24a034SAndrea Collamati 41*7b24a034SAndrea Collamati #define MCP4728_RDY_MASK BIT(7) 42*7b24a034SAndrea Collamati 43*7b24a034SAndrea Collamati #define MCP4728_MW_CMD 0x08 /* Multiwrite Command */ 44*7b24a034SAndrea Collamati #define MCP4728_SW_CMD 0x0A /* Sequential Write Command with EEPROM */ 45*7b24a034SAndrea Collamati 46*7b24a034SAndrea Collamati #define MCP4728_READ_RESPONSE_LEN (MCP4728_N_CHANNELS * 3 * 2) 47*7b24a034SAndrea Collamati #define MCP4728_WRITE_EEPROM_LEN (1 + MCP4728_N_CHANNELS * 2) 48*7b24a034SAndrea Collamati 49*7b24a034SAndrea Collamati enum vref_mode { 50*7b24a034SAndrea Collamati MCP4728_VREF_EXTERNAL_VDD = 0, 51*7b24a034SAndrea Collamati MCP4728_VREF_INTERNAL_2048mV = 1, 52*7b24a034SAndrea Collamati }; 53*7b24a034SAndrea Collamati 54*7b24a034SAndrea Collamati enum gain_mode { 55*7b24a034SAndrea Collamati MCP4728_GAIN_X1 = 0, 56*7b24a034SAndrea Collamati MCP4728_GAIN_X2 = 1, 57*7b24a034SAndrea Collamati }; 58*7b24a034SAndrea Collamati 59*7b24a034SAndrea Collamati enum iio_powerdown_mode { 60*7b24a034SAndrea Collamati MCP4728_IIO_1K, 61*7b24a034SAndrea Collamati MCP4728_IIO_100K, 62*7b24a034SAndrea Collamati MCP4728_IIO_500K, 63*7b24a034SAndrea Collamati }; 64*7b24a034SAndrea Collamati 65*7b24a034SAndrea Collamati struct mcp4728_channel_data { 66*7b24a034SAndrea Collamati enum vref_mode ref_mode; 67*7b24a034SAndrea Collamati enum iio_powerdown_mode pd_mode; 68*7b24a034SAndrea Collamati enum gain_mode g_mode; 69*7b24a034SAndrea Collamati u16 dac_value; 70*7b24a034SAndrea Collamati }; 71*7b24a034SAndrea Collamati 72*7b24a034SAndrea Collamati /* MCP4728 Full Scale Ranges 73*7b24a034SAndrea Collamati * the device available ranges are 74*7b24a034SAndrea Collamati * - VREF = VDD FSR = from 0.0V to VDD 75*7b24a034SAndrea Collamati * - VREF = Internal Gain = 1 FSR = from 0.0V to VREF 76*7b24a034SAndrea Collamati * - VREF = Internal Gain = 2 FSR = from 0.0V to 2*VREF 77*7b24a034SAndrea Collamati */ 78*7b24a034SAndrea Collamati enum mcp4728_scale { 79*7b24a034SAndrea Collamati MCP4728_SCALE_VDD, 80*7b24a034SAndrea Collamati MCP4728_SCALE_VINT_NO_GAIN, 81*7b24a034SAndrea Collamati MCP4728_SCALE_VINT_GAIN_X2, 82*7b24a034SAndrea Collamati MCP4728_N_SCALES 83*7b24a034SAndrea Collamati }; 84*7b24a034SAndrea Collamati 85*7b24a034SAndrea Collamati struct mcp4728_data { 86*7b24a034SAndrea Collamati struct i2c_client *client; 87*7b24a034SAndrea Collamati struct regulator *vdd_reg; 88*7b24a034SAndrea Collamati bool powerdown; 89*7b24a034SAndrea Collamati int scales_avail[MCP4728_N_SCALES * 2]; 90*7b24a034SAndrea Collamati struct mcp4728_channel_data chdata[MCP4728_N_CHANNELS]; 91*7b24a034SAndrea Collamati }; 92*7b24a034SAndrea Collamati 93*7b24a034SAndrea Collamati #define MCP4728_CHAN(chan) { \ 94*7b24a034SAndrea Collamati .type = IIO_VOLTAGE, \ 95*7b24a034SAndrea Collamati .output = 1, \ 96*7b24a034SAndrea Collamati .indexed = 1, \ 97*7b24a034SAndrea Collamati .channel = chan, \ 98*7b24a034SAndrea Collamati .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 99*7b24a034SAndrea Collamati BIT(IIO_CHAN_INFO_SCALE), \ 100*7b24a034SAndrea Collamati .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ 101*7b24a034SAndrea Collamati .ext_info = mcp4728_ext_info, \ 102*7b24a034SAndrea Collamati } 103*7b24a034SAndrea Collamati 104*7b24a034SAndrea Collamati static int mcp4728_suspend(struct device *dev); 105*7b24a034SAndrea Collamati static int mcp4728_resume(struct device *dev); 106*7b24a034SAndrea Collamati 107*7b24a034SAndrea Collamati static ssize_t mcp4728_store_eeprom(struct device *dev, 108*7b24a034SAndrea Collamati struct device_attribute *attr, 109*7b24a034SAndrea Collamati const char *buf, size_t len) 110*7b24a034SAndrea Collamati { 111*7b24a034SAndrea Collamati struct iio_dev *indio_dev = dev_to_iio_dev(dev); 112*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 113*7b24a034SAndrea Collamati u8 outbuf[MCP4728_WRITE_EEPROM_LEN]; 114*7b24a034SAndrea Collamati int tries = 20; 115*7b24a034SAndrea Collamati u8 inbuf[3]; 116*7b24a034SAndrea Collamati bool state; 117*7b24a034SAndrea Collamati int ret; 118*7b24a034SAndrea Collamati unsigned int i; 119*7b24a034SAndrea Collamati 120*7b24a034SAndrea Collamati ret = kstrtobool(buf, &state); 121*7b24a034SAndrea Collamati if (ret < 0) 122*7b24a034SAndrea Collamati return ret; 123*7b24a034SAndrea Collamati 124*7b24a034SAndrea Collamati if (!state) 125*7b24a034SAndrea Collamati return 0; 126*7b24a034SAndrea Collamati 127*7b24a034SAndrea Collamati outbuf[0] = FIELD_PREP(MCP4728_CMD_MASK, MCP4728_SW_CMD); 128*7b24a034SAndrea Collamati 129*7b24a034SAndrea Collamati for (i = 0; i < MCP4728_N_CHANNELS; i++) { 130*7b24a034SAndrea Collamati struct mcp4728_channel_data *ch = &data->chdata[i]; 131*7b24a034SAndrea Collamati int offset = 1 + i * 2; 132*7b24a034SAndrea Collamati 133*7b24a034SAndrea Collamati outbuf[offset] = FIELD_PREP(MCP4728_VREF_MASK, ch->ref_mode); 134*7b24a034SAndrea Collamati 135*7b24a034SAndrea Collamati if (data->powerdown) { 136*7b24a034SAndrea Collamati u8 mcp4728_pd_mode = ch->pd_mode + 1; 137*7b24a034SAndrea Collamati 138*7b24a034SAndrea Collamati outbuf[offset] |= FIELD_PREP(MCP4728_PDMODE_MASK, 139*7b24a034SAndrea Collamati mcp4728_pd_mode); 140*7b24a034SAndrea Collamati } 141*7b24a034SAndrea Collamati 142*7b24a034SAndrea Collamati outbuf[offset] |= FIELD_PREP(MCP4728_GAIN_MASK, ch->g_mode); 143*7b24a034SAndrea Collamati outbuf[offset] |= 144*7b24a034SAndrea Collamati FIELD_PREP(MCP4728_DAC_H_MASK, ch->dac_value >> 8); 145*7b24a034SAndrea Collamati outbuf[offset + 1] = 146*7b24a034SAndrea Collamati FIELD_PREP(MCP4728_DAC_L_MASK, ch->dac_value); 147*7b24a034SAndrea Collamati } 148*7b24a034SAndrea Collamati 149*7b24a034SAndrea Collamati ret = i2c_master_send(data->client, outbuf, MCP4728_WRITE_EEPROM_LEN); 150*7b24a034SAndrea Collamati if (ret < 0) 151*7b24a034SAndrea Collamati return ret; 152*7b24a034SAndrea Collamati else if (ret != MCP4728_WRITE_EEPROM_LEN) 153*7b24a034SAndrea Collamati return -EIO; 154*7b24a034SAndrea Collamati 155*7b24a034SAndrea Collamati /* wait RDY signal for write complete, takes up to 50ms */ 156*7b24a034SAndrea Collamati while (tries--) { 157*7b24a034SAndrea Collamati msleep(20); 158*7b24a034SAndrea Collamati ret = i2c_master_recv(data->client, inbuf, 3); 159*7b24a034SAndrea Collamati if (ret < 0) 160*7b24a034SAndrea Collamati return ret; 161*7b24a034SAndrea Collamati else if (ret != 3) 162*7b24a034SAndrea Collamati return -EIO; 163*7b24a034SAndrea Collamati 164*7b24a034SAndrea Collamati if (FIELD_GET(MCP4728_RDY_MASK, inbuf[0])) 165*7b24a034SAndrea Collamati break; 166*7b24a034SAndrea Collamati } 167*7b24a034SAndrea Collamati 168*7b24a034SAndrea Collamati if (tries < 0) { 169*7b24a034SAndrea Collamati dev_err(&data->client->dev, "%s failed, incomplete\n", 170*7b24a034SAndrea Collamati __func__); 171*7b24a034SAndrea Collamati return -EIO; 172*7b24a034SAndrea Collamati } 173*7b24a034SAndrea Collamati return len; 174*7b24a034SAndrea Collamati } 175*7b24a034SAndrea Collamati 176*7b24a034SAndrea Collamati static IIO_DEVICE_ATTR(store_eeprom, 0200, NULL, mcp4728_store_eeprom, 0); 177*7b24a034SAndrea Collamati 178*7b24a034SAndrea Collamati static struct attribute *mcp4728_attributes[] = { 179*7b24a034SAndrea Collamati &iio_dev_attr_store_eeprom.dev_attr.attr, 180*7b24a034SAndrea Collamati NULL, 181*7b24a034SAndrea Collamati }; 182*7b24a034SAndrea Collamati 183*7b24a034SAndrea Collamati static const struct attribute_group mcp4728_attribute_group = { 184*7b24a034SAndrea Collamati .attrs = mcp4728_attributes, 185*7b24a034SAndrea Collamati }; 186*7b24a034SAndrea Collamati 187*7b24a034SAndrea Collamati static int mcp4728_program_channel_cfg(int channel, struct iio_dev *indio_dev) 188*7b24a034SAndrea Collamati { 189*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 190*7b24a034SAndrea Collamati struct mcp4728_channel_data *ch = &data->chdata[channel]; 191*7b24a034SAndrea Collamati u8 outbuf[3]; 192*7b24a034SAndrea Collamati int ret; 193*7b24a034SAndrea Collamati 194*7b24a034SAndrea Collamati outbuf[0] = FIELD_PREP(MCP4728_CMD_MASK, MCP4728_MW_CMD); 195*7b24a034SAndrea Collamati outbuf[0] |= FIELD_PREP(MCP4728_CHSEL_MASK, channel); 196*7b24a034SAndrea Collamati outbuf[0] |= FIELD_PREP(MCP4728_UDAC_MASK, 0); 197*7b24a034SAndrea Collamati 198*7b24a034SAndrea Collamati outbuf[1] = FIELD_PREP(MCP4728_VREF_MASK, ch->ref_mode); 199*7b24a034SAndrea Collamati 200*7b24a034SAndrea Collamati if (data->powerdown) 201*7b24a034SAndrea Collamati outbuf[1] |= FIELD_PREP(MCP4728_PDMODE_MASK, ch->pd_mode + 1); 202*7b24a034SAndrea Collamati 203*7b24a034SAndrea Collamati outbuf[1] |= FIELD_PREP(MCP4728_GAIN_MASK, ch->g_mode); 204*7b24a034SAndrea Collamati outbuf[1] |= FIELD_PREP(MCP4728_DAC_H_MASK, ch->dac_value >> 8); 205*7b24a034SAndrea Collamati outbuf[2] = FIELD_PREP(MCP4728_DAC_L_MASK, ch->dac_value); 206*7b24a034SAndrea Collamati 207*7b24a034SAndrea Collamati ret = i2c_master_send(data->client, outbuf, 3); 208*7b24a034SAndrea Collamati if (ret < 0) 209*7b24a034SAndrea Collamati return ret; 210*7b24a034SAndrea Collamati else if (ret != 3) 211*7b24a034SAndrea Collamati return -EIO; 212*7b24a034SAndrea Collamati 213*7b24a034SAndrea Collamati return 0; 214*7b24a034SAndrea Collamati } 215*7b24a034SAndrea Collamati 216*7b24a034SAndrea Collamati static const char *const mcp4728_powerdown_modes[] = { "1kohm_to_gnd", 217*7b24a034SAndrea Collamati "100kohm_to_gnd", 218*7b24a034SAndrea Collamati "500kohm_to_gnd" }; 219*7b24a034SAndrea Collamati 220*7b24a034SAndrea Collamati static int mcp4728_get_powerdown_mode(struct iio_dev *indio_dev, 221*7b24a034SAndrea Collamati const struct iio_chan_spec *chan) 222*7b24a034SAndrea Collamati { 223*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 224*7b24a034SAndrea Collamati 225*7b24a034SAndrea Collamati return data->chdata[chan->channel].pd_mode; 226*7b24a034SAndrea Collamati } 227*7b24a034SAndrea Collamati 228*7b24a034SAndrea Collamati static int mcp4728_set_powerdown_mode(struct iio_dev *indio_dev, 229*7b24a034SAndrea Collamati const struct iio_chan_spec *chan, 230*7b24a034SAndrea Collamati unsigned int mode) 231*7b24a034SAndrea Collamati { 232*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 233*7b24a034SAndrea Collamati 234*7b24a034SAndrea Collamati data->chdata[chan->channel].pd_mode = mode; 235*7b24a034SAndrea Collamati 236*7b24a034SAndrea Collamati return 0; 237*7b24a034SAndrea Collamati } 238*7b24a034SAndrea Collamati 239*7b24a034SAndrea Collamati static ssize_t mcp4728_read_powerdown(struct iio_dev *indio_dev, 240*7b24a034SAndrea Collamati uintptr_t private, 241*7b24a034SAndrea Collamati const struct iio_chan_spec *chan, 242*7b24a034SAndrea Collamati char *buf) 243*7b24a034SAndrea Collamati { 244*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 245*7b24a034SAndrea Collamati 246*7b24a034SAndrea Collamati return sysfs_emit(buf, "%d\n", data->powerdown); 247*7b24a034SAndrea Collamati } 248*7b24a034SAndrea Collamati 249*7b24a034SAndrea Collamati static ssize_t mcp4728_write_powerdown(struct iio_dev *indio_dev, 250*7b24a034SAndrea Collamati uintptr_t private, 251*7b24a034SAndrea Collamati const struct iio_chan_spec *chan, 252*7b24a034SAndrea Collamati const char *buf, size_t len) 253*7b24a034SAndrea Collamati { 254*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 255*7b24a034SAndrea Collamati bool state; 256*7b24a034SAndrea Collamati int ret; 257*7b24a034SAndrea Collamati 258*7b24a034SAndrea Collamati ret = kstrtobool(buf, &state); 259*7b24a034SAndrea Collamati if (ret) 260*7b24a034SAndrea Collamati return ret; 261*7b24a034SAndrea Collamati 262*7b24a034SAndrea Collamati if (state) 263*7b24a034SAndrea Collamati ret = mcp4728_suspend(&data->client->dev); 264*7b24a034SAndrea Collamati else 265*7b24a034SAndrea Collamati ret = mcp4728_resume(&data->client->dev); 266*7b24a034SAndrea Collamati 267*7b24a034SAndrea Collamati if (ret < 0) 268*7b24a034SAndrea Collamati return ret; 269*7b24a034SAndrea Collamati 270*7b24a034SAndrea Collamati return len; 271*7b24a034SAndrea Collamati } 272*7b24a034SAndrea Collamati 273*7b24a034SAndrea Collamati static const struct iio_enum mcp4728_powerdown_mode_enum = { 274*7b24a034SAndrea Collamati .items = mcp4728_powerdown_modes, 275*7b24a034SAndrea Collamati .num_items = ARRAY_SIZE(mcp4728_powerdown_modes), 276*7b24a034SAndrea Collamati .get = mcp4728_get_powerdown_mode, 277*7b24a034SAndrea Collamati .set = mcp4728_set_powerdown_mode, 278*7b24a034SAndrea Collamati }; 279*7b24a034SAndrea Collamati 280*7b24a034SAndrea Collamati static const struct iio_chan_spec_ext_info mcp4728_ext_info[] = { 281*7b24a034SAndrea Collamati { 282*7b24a034SAndrea Collamati .name = "powerdown", 283*7b24a034SAndrea Collamati .read = mcp4728_read_powerdown, 284*7b24a034SAndrea Collamati .write = mcp4728_write_powerdown, 285*7b24a034SAndrea Collamati .shared = IIO_SEPARATE, 286*7b24a034SAndrea Collamati }, 287*7b24a034SAndrea Collamati IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4728_powerdown_mode_enum), 288*7b24a034SAndrea Collamati IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, 289*7b24a034SAndrea Collamati &mcp4728_powerdown_mode_enum), 290*7b24a034SAndrea Collamati {}, 291*7b24a034SAndrea Collamati }; 292*7b24a034SAndrea Collamati 293*7b24a034SAndrea Collamati static const struct iio_chan_spec mcp4728_channels[MCP4728_N_CHANNELS] = { 294*7b24a034SAndrea Collamati MCP4728_CHAN(0), 295*7b24a034SAndrea Collamati MCP4728_CHAN(1), 296*7b24a034SAndrea Collamati MCP4728_CHAN(2), 297*7b24a034SAndrea Collamati MCP4728_CHAN(3), 298*7b24a034SAndrea Collamati }; 299*7b24a034SAndrea Collamati 300*7b24a034SAndrea Collamati static void mcp4728_get_scale_avail(enum mcp4728_scale scale, 301*7b24a034SAndrea Collamati struct mcp4728_data *data, int *val, 302*7b24a034SAndrea Collamati int *val2) 303*7b24a034SAndrea Collamati { 304*7b24a034SAndrea Collamati *val = data->scales_avail[scale * 2]; 305*7b24a034SAndrea Collamati *val2 = data->scales_avail[scale * 2 + 1]; 306*7b24a034SAndrea Collamati } 307*7b24a034SAndrea Collamati 308*7b24a034SAndrea Collamati static void mcp4728_get_scale(int channel, struct mcp4728_data *data, int *val, 309*7b24a034SAndrea Collamati int *val2) 310*7b24a034SAndrea Collamati { 311*7b24a034SAndrea Collamati int ref_mode = data->chdata[channel].ref_mode; 312*7b24a034SAndrea Collamati int g_mode = data->chdata[channel].g_mode; 313*7b24a034SAndrea Collamati 314*7b24a034SAndrea Collamati if (ref_mode == MCP4728_VREF_EXTERNAL_VDD) { 315*7b24a034SAndrea Collamati mcp4728_get_scale_avail(MCP4728_SCALE_VDD, data, val, val2); 316*7b24a034SAndrea Collamati } else { 317*7b24a034SAndrea Collamati if (g_mode == MCP4728_GAIN_X1) { 318*7b24a034SAndrea Collamati mcp4728_get_scale_avail(MCP4728_SCALE_VINT_NO_GAIN, 319*7b24a034SAndrea Collamati data, val, val2); 320*7b24a034SAndrea Collamati } else { 321*7b24a034SAndrea Collamati mcp4728_get_scale_avail(MCP4728_SCALE_VINT_GAIN_X2, 322*7b24a034SAndrea Collamati data, val, val2); 323*7b24a034SAndrea Collamati } 324*7b24a034SAndrea Collamati } 325*7b24a034SAndrea Collamati } 326*7b24a034SAndrea Collamati 327*7b24a034SAndrea Collamati static int mcp4728_find_matching_scale(struct mcp4728_data *data, int val, 328*7b24a034SAndrea Collamati int val2) 329*7b24a034SAndrea Collamati { 330*7b24a034SAndrea Collamati for (int i = 0; i < MCP4728_N_SCALES; i++) { 331*7b24a034SAndrea Collamati if (data->scales_avail[i * 2] == val && 332*7b24a034SAndrea Collamati data->scales_avail[i * 2 + 1] == val2) 333*7b24a034SAndrea Collamati return i; 334*7b24a034SAndrea Collamati } 335*7b24a034SAndrea Collamati return -EINVAL; 336*7b24a034SAndrea Collamati } 337*7b24a034SAndrea Collamati 338*7b24a034SAndrea Collamati static int mcp4728_set_scale(int channel, struct mcp4728_data *data, int val, 339*7b24a034SAndrea Collamati int val2) 340*7b24a034SAndrea Collamati { 341*7b24a034SAndrea Collamati int scale = mcp4728_find_matching_scale(data, val, val2); 342*7b24a034SAndrea Collamati 343*7b24a034SAndrea Collamati if (scale < 0) 344*7b24a034SAndrea Collamati return scale; 345*7b24a034SAndrea Collamati 346*7b24a034SAndrea Collamati switch (scale) { 347*7b24a034SAndrea Collamati case MCP4728_SCALE_VDD: 348*7b24a034SAndrea Collamati data->chdata[channel].ref_mode = MCP4728_VREF_EXTERNAL_VDD; 349*7b24a034SAndrea Collamati return 0; 350*7b24a034SAndrea Collamati case MCP4728_SCALE_VINT_NO_GAIN: 351*7b24a034SAndrea Collamati data->chdata[channel].ref_mode = MCP4728_VREF_INTERNAL_2048mV; 352*7b24a034SAndrea Collamati data->chdata[channel].g_mode = MCP4728_GAIN_X1; 353*7b24a034SAndrea Collamati return 0; 354*7b24a034SAndrea Collamati case MCP4728_SCALE_VINT_GAIN_X2: 355*7b24a034SAndrea Collamati data->chdata[channel].ref_mode = MCP4728_VREF_INTERNAL_2048mV; 356*7b24a034SAndrea Collamati data->chdata[channel].g_mode = MCP4728_GAIN_X2; 357*7b24a034SAndrea Collamati return 0; 358*7b24a034SAndrea Collamati default: 359*7b24a034SAndrea Collamati return -EINVAL; 360*7b24a034SAndrea Collamati } 361*7b24a034SAndrea Collamati } 362*7b24a034SAndrea Collamati 363*7b24a034SAndrea Collamati static int mcp4728_read_raw(struct iio_dev *indio_dev, 364*7b24a034SAndrea Collamati struct iio_chan_spec const *chan, int *val, 365*7b24a034SAndrea Collamati int *val2, long mask) 366*7b24a034SAndrea Collamati { 367*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 368*7b24a034SAndrea Collamati 369*7b24a034SAndrea Collamati switch (mask) { 370*7b24a034SAndrea Collamati case IIO_CHAN_INFO_RAW: 371*7b24a034SAndrea Collamati *val = data->chdata[chan->channel].dac_value; 372*7b24a034SAndrea Collamati return IIO_VAL_INT; 373*7b24a034SAndrea Collamati case IIO_CHAN_INFO_SCALE: 374*7b24a034SAndrea Collamati mcp4728_get_scale(chan->channel, data, val, val2); 375*7b24a034SAndrea Collamati return IIO_VAL_INT_PLUS_MICRO; 376*7b24a034SAndrea Collamati } 377*7b24a034SAndrea Collamati return -EINVAL; 378*7b24a034SAndrea Collamati } 379*7b24a034SAndrea Collamati 380*7b24a034SAndrea Collamati static int mcp4728_write_raw(struct iio_dev *indio_dev, 381*7b24a034SAndrea Collamati struct iio_chan_spec const *chan, int val, 382*7b24a034SAndrea Collamati int val2, long mask) 383*7b24a034SAndrea Collamati { 384*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 385*7b24a034SAndrea Collamati int ret; 386*7b24a034SAndrea Collamati 387*7b24a034SAndrea Collamati switch (mask) { 388*7b24a034SAndrea Collamati case IIO_CHAN_INFO_RAW: 389*7b24a034SAndrea Collamati if (val < 0 || val > GENMASK(MCP4728_RESOLUTION - 1, 0)) 390*7b24a034SAndrea Collamati return -EINVAL; 391*7b24a034SAndrea Collamati data->chdata[chan->channel].dac_value = val; 392*7b24a034SAndrea Collamati return mcp4728_program_channel_cfg(chan->channel, indio_dev); 393*7b24a034SAndrea Collamati case IIO_CHAN_INFO_SCALE: 394*7b24a034SAndrea Collamati ret = mcp4728_set_scale(chan->channel, data, val, val2); 395*7b24a034SAndrea Collamati if (ret) 396*7b24a034SAndrea Collamati return ret; 397*7b24a034SAndrea Collamati 398*7b24a034SAndrea Collamati return mcp4728_program_channel_cfg(chan->channel, indio_dev); 399*7b24a034SAndrea Collamati default: 400*7b24a034SAndrea Collamati return -EINVAL; 401*7b24a034SAndrea Collamati } 402*7b24a034SAndrea Collamati } 403*7b24a034SAndrea Collamati 404*7b24a034SAndrea Collamati static void mcp4728_init_scale_avail(enum mcp4728_scale scale, int vref_mv, 405*7b24a034SAndrea Collamati struct mcp4728_data *data) 406*7b24a034SAndrea Collamati { 407*7b24a034SAndrea Collamati s64 tmp; 408*7b24a034SAndrea Collamati int value_micro; 409*7b24a034SAndrea Collamati int value_int; 410*7b24a034SAndrea Collamati 411*7b24a034SAndrea Collamati tmp = (s64)vref_mv * 1000000LL >> MCP4728_RESOLUTION; 412*7b24a034SAndrea Collamati value_int = div_s64_rem(tmp, 1000000LL, &value_micro); 413*7b24a034SAndrea Collamati 414*7b24a034SAndrea Collamati data->scales_avail[scale * 2] = value_int; 415*7b24a034SAndrea Collamati data->scales_avail[scale * 2 + 1] = value_micro; 416*7b24a034SAndrea Collamati } 417*7b24a034SAndrea Collamati 418*7b24a034SAndrea Collamati static int mcp4728_init_scales_avail(struct mcp4728_data *data) 419*7b24a034SAndrea Collamati { 420*7b24a034SAndrea Collamati int ret; 421*7b24a034SAndrea Collamati 422*7b24a034SAndrea Collamati ret = regulator_get_voltage(data->vdd_reg); 423*7b24a034SAndrea Collamati if (ret < 0) 424*7b24a034SAndrea Collamati return ret; 425*7b24a034SAndrea Collamati 426*7b24a034SAndrea Collamati mcp4728_init_scale_avail(MCP4728_SCALE_VDD, ret / 1000, data); 427*7b24a034SAndrea Collamati mcp4728_init_scale_avail(MCP4728_SCALE_VINT_NO_GAIN, 2048, data); 428*7b24a034SAndrea Collamati mcp4728_init_scale_avail(MCP4728_SCALE_VINT_GAIN_X2, 4096, data); 429*7b24a034SAndrea Collamati 430*7b24a034SAndrea Collamati return 0; 431*7b24a034SAndrea Collamati } 432*7b24a034SAndrea Collamati 433*7b24a034SAndrea Collamati static int mcp4728_read_avail(struct iio_dev *indio_dev, 434*7b24a034SAndrea Collamati struct iio_chan_spec const *chan, 435*7b24a034SAndrea Collamati const int **vals, int *type, int *length, 436*7b24a034SAndrea Collamati long info) 437*7b24a034SAndrea Collamati { 438*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 439*7b24a034SAndrea Collamati 440*7b24a034SAndrea Collamati switch (info) { 441*7b24a034SAndrea Collamati case IIO_CHAN_INFO_SCALE: 442*7b24a034SAndrea Collamati *type = IIO_VAL_INT_PLUS_MICRO; 443*7b24a034SAndrea Collamati 444*7b24a034SAndrea Collamati switch (chan->type) { 445*7b24a034SAndrea Collamati case IIO_VOLTAGE: 446*7b24a034SAndrea Collamati *vals = data->scales_avail; 447*7b24a034SAndrea Collamati *length = MCP4728_N_SCALES * 2; 448*7b24a034SAndrea Collamati return IIO_AVAIL_LIST; 449*7b24a034SAndrea Collamati default: 450*7b24a034SAndrea Collamati return -EINVAL; 451*7b24a034SAndrea Collamati } 452*7b24a034SAndrea Collamati default: 453*7b24a034SAndrea Collamati return -EINVAL; 454*7b24a034SAndrea Collamati } 455*7b24a034SAndrea Collamati } 456*7b24a034SAndrea Collamati 457*7b24a034SAndrea Collamati static const struct iio_info mcp4728_info = { 458*7b24a034SAndrea Collamati .read_raw = mcp4728_read_raw, 459*7b24a034SAndrea Collamati .write_raw = mcp4728_write_raw, 460*7b24a034SAndrea Collamati .read_avail = &mcp4728_read_avail, 461*7b24a034SAndrea Collamati .attrs = &mcp4728_attribute_group, 462*7b24a034SAndrea Collamati }; 463*7b24a034SAndrea Collamati 464*7b24a034SAndrea Collamati static int mcp4728_suspend(struct device *dev) 465*7b24a034SAndrea Collamati { 466*7b24a034SAndrea Collamati struct iio_dev *indio_dev = dev_get_drvdata(dev); 467*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 468*7b24a034SAndrea Collamati unsigned int i; 469*7b24a034SAndrea Collamati 470*7b24a034SAndrea Collamati data->powerdown = true; 471*7b24a034SAndrea Collamati 472*7b24a034SAndrea Collamati for (i = 0; i < MCP4728_N_CHANNELS; i++) { 473*7b24a034SAndrea Collamati int err = mcp4728_program_channel_cfg(i, indio_dev); 474*7b24a034SAndrea Collamati 475*7b24a034SAndrea Collamati if (err) 476*7b24a034SAndrea Collamati return err; 477*7b24a034SAndrea Collamati } 478*7b24a034SAndrea Collamati return 0; 479*7b24a034SAndrea Collamati } 480*7b24a034SAndrea Collamati 481*7b24a034SAndrea Collamati static int mcp4728_resume(struct device *dev) 482*7b24a034SAndrea Collamati { 483*7b24a034SAndrea Collamati struct iio_dev *indio_dev = dev_get_drvdata(dev); 484*7b24a034SAndrea Collamati struct mcp4728_data *data = iio_priv(indio_dev); 485*7b24a034SAndrea Collamati int err = 0; 486*7b24a034SAndrea Collamati unsigned int i; 487*7b24a034SAndrea Collamati 488*7b24a034SAndrea Collamati data->powerdown = false; 489*7b24a034SAndrea Collamati 490*7b24a034SAndrea Collamati for (i = 0; i < MCP4728_N_CHANNELS; i++) { 491*7b24a034SAndrea Collamati int ret = mcp4728_program_channel_cfg(i, indio_dev); 492*7b24a034SAndrea Collamati 493*7b24a034SAndrea Collamati if (ret) 494*7b24a034SAndrea Collamati err = ret; 495*7b24a034SAndrea Collamati } 496*7b24a034SAndrea Collamati return err; 497*7b24a034SAndrea Collamati } 498*7b24a034SAndrea Collamati 499*7b24a034SAndrea Collamati static DEFINE_SIMPLE_DEV_PM_OPS(mcp4728_pm_ops, mcp4728_suspend, 500*7b24a034SAndrea Collamati mcp4728_resume); 501*7b24a034SAndrea Collamati 502*7b24a034SAndrea Collamati static int mcp4728_init_channels_data(struct mcp4728_data *data) 503*7b24a034SAndrea Collamati { 504*7b24a034SAndrea Collamati u8 inbuf[MCP4728_READ_RESPONSE_LEN]; 505*7b24a034SAndrea Collamati int ret; 506*7b24a034SAndrea Collamati unsigned int i; 507*7b24a034SAndrea Collamati 508*7b24a034SAndrea Collamati ret = i2c_master_recv(data->client, inbuf, MCP4728_READ_RESPONSE_LEN); 509*7b24a034SAndrea Collamati if (ret < 0) { 510*7b24a034SAndrea Collamati return dev_err_probe(&data->client->dev, ret, 511*7b24a034SAndrea Collamati "failed to read mcp4728 conf.\n"); 512*7b24a034SAndrea Collamati } else if (ret != MCP4728_READ_RESPONSE_LEN) { 513*7b24a034SAndrea Collamati return dev_err_probe(&data->client->dev, -EIO, 514*7b24a034SAndrea Collamati "failed to read mcp4728 conf. Wrong Response Len ret=%d\n", 515*7b24a034SAndrea Collamati ret); 516*7b24a034SAndrea Collamati } 517*7b24a034SAndrea Collamati 518*7b24a034SAndrea Collamati for (i = 0; i < MCP4728_N_CHANNELS; i++) { 519*7b24a034SAndrea Collamati struct mcp4728_channel_data *ch = &data->chdata[i]; 520*7b24a034SAndrea Collamati u8 r2 = inbuf[i * 6 + 1]; 521*7b24a034SAndrea Collamati u8 r3 = inbuf[i * 6 + 2]; 522*7b24a034SAndrea Collamati 523*7b24a034SAndrea Collamati ch->dac_value = FIELD_GET(MCP4728_DAC_H_MASK, r2) << 8 | 524*7b24a034SAndrea Collamati FIELD_GET(MCP4728_DAC_L_MASK, r3); 525*7b24a034SAndrea Collamati ch->ref_mode = FIELD_GET(MCP4728_VREF_MASK, r2); 526*7b24a034SAndrea Collamati ch->pd_mode = FIELD_GET(MCP4728_PDMODE_MASK, r2); 527*7b24a034SAndrea Collamati ch->g_mode = FIELD_GET(MCP4728_GAIN_MASK, r2); 528*7b24a034SAndrea Collamati } 529*7b24a034SAndrea Collamati 530*7b24a034SAndrea Collamati return 0; 531*7b24a034SAndrea Collamati } 532*7b24a034SAndrea Collamati 533*7b24a034SAndrea Collamati static void mcp4728_reg_disable(void *reg) 534*7b24a034SAndrea Collamati { 535*7b24a034SAndrea Collamati regulator_disable(reg); 536*7b24a034SAndrea Collamati } 537*7b24a034SAndrea Collamati 538*7b24a034SAndrea Collamati static int mcp4728_probe(struct i2c_client *client) 539*7b24a034SAndrea Collamati { 540*7b24a034SAndrea Collamati const struct i2c_device_id *id = i2c_client_get_device_id(client); 541*7b24a034SAndrea Collamati struct mcp4728_data *data; 542*7b24a034SAndrea Collamati struct iio_dev *indio_dev; 543*7b24a034SAndrea Collamati int err; 544*7b24a034SAndrea Collamati 545*7b24a034SAndrea Collamati indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 546*7b24a034SAndrea Collamati if (!indio_dev) 547*7b24a034SAndrea Collamati return -ENOMEM; 548*7b24a034SAndrea Collamati 549*7b24a034SAndrea Collamati data = iio_priv(indio_dev); 550*7b24a034SAndrea Collamati i2c_set_clientdata(client, indio_dev); 551*7b24a034SAndrea Collamati data->client = client; 552*7b24a034SAndrea Collamati 553*7b24a034SAndrea Collamati data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); 554*7b24a034SAndrea Collamati if (IS_ERR(data->vdd_reg)) 555*7b24a034SAndrea Collamati return PTR_ERR(data->vdd_reg); 556*7b24a034SAndrea Collamati 557*7b24a034SAndrea Collamati err = regulator_enable(data->vdd_reg); 558*7b24a034SAndrea Collamati if (err) 559*7b24a034SAndrea Collamati return err; 560*7b24a034SAndrea Collamati 561*7b24a034SAndrea Collamati err = devm_add_action_or_reset(&client->dev, mcp4728_reg_disable, 562*7b24a034SAndrea Collamati data->vdd_reg); 563*7b24a034SAndrea Collamati if (err) 564*7b24a034SAndrea Collamati return err; 565*7b24a034SAndrea Collamati 566*7b24a034SAndrea Collamati /* 567*7b24a034SAndrea Collamati * MCP4728 has internal EEPROM that save each channel boot 568*7b24a034SAndrea Collamati * configuration. It means that device configuration is unknown to the 569*7b24a034SAndrea Collamati * driver at kernel boot. mcp4728_init_channels_data() reads back DAC 570*7b24a034SAndrea Collamati * settings and stores them in data structure. 571*7b24a034SAndrea Collamati */ 572*7b24a034SAndrea Collamati err = mcp4728_init_channels_data(data); 573*7b24a034SAndrea Collamati if (err) { 574*7b24a034SAndrea Collamati return dev_err_probe(&client->dev, err, 575*7b24a034SAndrea Collamati "failed to read mcp4728 current configuration\n"); 576*7b24a034SAndrea Collamati } 577*7b24a034SAndrea Collamati 578*7b24a034SAndrea Collamati err = mcp4728_init_scales_avail(data); 579*7b24a034SAndrea Collamati if (err) { 580*7b24a034SAndrea Collamati return dev_err_probe(&client->dev, err, 581*7b24a034SAndrea Collamati "failed to init scales\n"); 582*7b24a034SAndrea Collamati } 583*7b24a034SAndrea Collamati 584*7b24a034SAndrea Collamati indio_dev->name = id->name; 585*7b24a034SAndrea Collamati indio_dev->info = &mcp4728_info; 586*7b24a034SAndrea Collamati indio_dev->channels = mcp4728_channels; 587*7b24a034SAndrea Collamati indio_dev->num_channels = MCP4728_N_CHANNELS; 588*7b24a034SAndrea Collamati indio_dev->modes = INDIO_DIRECT_MODE; 589*7b24a034SAndrea Collamati 590*7b24a034SAndrea Collamati return devm_iio_device_register(&client->dev, indio_dev); 591*7b24a034SAndrea Collamati } 592*7b24a034SAndrea Collamati 593*7b24a034SAndrea Collamati static const struct i2c_device_id mcp4728_id[] = { 594*7b24a034SAndrea Collamati { "mcp4728", 0 }, 595*7b24a034SAndrea Collamati {} 596*7b24a034SAndrea Collamati }; 597*7b24a034SAndrea Collamati MODULE_DEVICE_TABLE(i2c, mcp4728_id); 598*7b24a034SAndrea Collamati 599*7b24a034SAndrea Collamati static const struct of_device_id mcp4728_of_match[] = { 600*7b24a034SAndrea Collamati { .compatible = "microchip,mcp4728" }, 601*7b24a034SAndrea Collamati {} 602*7b24a034SAndrea Collamati }; 603*7b24a034SAndrea Collamati MODULE_DEVICE_TABLE(of, mcp4728_of_match); 604*7b24a034SAndrea Collamati 605*7b24a034SAndrea Collamati static struct i2c_driver mcp4728_driver = { 606*7b24a034SAndrea Collamati .driver = { 607*7b24a034SAndrea Collamati .name = "mcp4728", 608*7b24a034SAndrea Collamati .of_match_table = mcp4728_of_match, 609*7b24a034SAndrea Collamati .pm = pm_sleep_ptr(&mcp4728_pm_ops), 610*7b24a034SAndrea Collamati }, 611*7b24a034SAndrea Collamati .probe = mcp4728_probe, 612*7b24a034SAndrea Collamati .id_table = mcp4728_id, 613*7b24a034SAndrea Collamati }; 614*7b24a034SAndrea Collamati module_i2c_driver(mcp4728_driver); 615*7b24a034SAndrea Collamati 616*7b24a034SAndrea Collamati MODULE_AUTHOR("Andrea Collamati <andrea.collamati@gmail.com>"); 617*7b24a034SAndrea Collamati MODULE_DESCRIPTION("MCP4728 12-bit DAC"); 618*7b24a034SAndrea Collamati MODULE_LICENSE("GPL"); 619