1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * I2C driver for AD5696 and similar Digital to Analog Converters 4 * 5 * Copyright 2018 Analog Devices Inc. 6 */ 7 8 #include <linux/bitfield.h> 9 #include <linux/errno.h> 10 #include <linux/i2c.h> 11 #include <linux/module.h> 12 13 #include <asm/byteorder.h> 14 15 #include "ad5686.h" 16 17 static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) 18 { 19 struct i2c_client *i2c = to_i2c_client(st->dev); 20 struct i2c_msg msg[2] = { 21 { 22 .addr = i2c->addr, 23 .flags = i2c->flags, 24 .len = 3, 25 .buf = &st->data[0].d8[1], 26 }, 27 { 28 .addr = i2c->addr, 29 .flags = i2c->flags | I2C_M_RD, 30 .len = 2, 31 .buf = (char *)&st->data[0].d16, 32 }, 33 }; 34 int ret; 35 36 st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP) | 37 FIELD_PREP(AD5686_ADDR_MSK, addr)); 38 39 ret = i2c_transfer(i2c->adapter, msg, 2); 40 if (ret < 0) 41 return ret; 42 43 return be16_to_cpu(st->data[0].d16); 44 } 45 46 static int ad5686_i2c_write(struct ad5686_state *st, 47 u8 cmd, u8 addr, u16 val) 48 { 49 struct i2c_client *i2c = to_i2c_client(st->dev); 50 int ret; 51 52 st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | 53 FIELD_PREP(AD5686_ADDR_MSK, addr) | 54 FIELD_PREP(AD5686_DATA_MSK, val)); 55 56 ret = i2c_master_send(i2c, &st->data[0].d8[1], 3); 57 if (ret < 0) 58 return ret; 59 60 return (ret != 3) ? -EIO : 0; 61 } 62 63 static const struct ad5686_bus_ops ad5686_i2c_ops = { 64 .write = ad5686_i2c_write, 65 .read = ad5686_i2c_read, 66 }; 67 68 static int ad5686_i2c_probe(struct i2c_client *i2c) 69 { 70 const struct ad5686_chip_info *info; 71 72 info = i2c_get_match_data(i2c); 73 if (!info) 74 return -ENODATA; 75 76 return ad5686_probe(&i2c->dev, info, i2c->name, &ad5686_i2c_ops, NULL); 77 } 78 79 static const struct i2c_device_id ad5686_i2c_id[] = { 80 { .name = "ad5311r", .driver_data = (kernel_ulong_t)&ad5311r_chip_info }, 81 { .name = "ad5316r", .driver_data = (kernel_ulong_t)&ad5317r_chip_info }, 82 { .name = "ad5337r", .driver_data = (kernel_ulong_t)&ad5337r_chip_info }, 83 { .name = "ad5338r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info }, 84 { .name = "ad5671r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info }, 85 { .name = "ad5673r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info }, 86 { .name = "ad5675", .driver_data = (kernel_ulong_t)&ad5676_chip_info }, 87 { .name = "ad5675r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info }, 88 { .name = "ad5677r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info }, 89 { .name = "ad5691r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info }, 90 { .name = "ad5692r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info }, 91 { .name = "ad5693", .driver_data = (kernel_ulong_t)&ad5683_chip_info }, 92 { .name = "ad5693r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info }, 93 { .name = "ad5694", .driver_data = (kernel_ulong_t)&ad5684_chip_info }, 94 { .name = "ad5694r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info }, 95 { .name = "ad5695r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, 96 { .name = "ad5696", .driver_data = (kernel_ulong_t)&ad5686_chip_info }, 97 { .name = "ad5696r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info }, 98 { .name = "ad5697r", .driver_data = (kernel_ulong_t)&ad5687r_chip_info }, 99 { } 100 }; 101 MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); 102 103 static const struct of_device_id ad5686_of_match[] = { 104 { .compatible = "adi,ad5311r", .data = &ad5311r_chip_info }, 105 { .compatible = "adi,ad5316r", .data = &ad5317r_chip_info }, 106 { .compatible = "adi,ad5337r", .data = &ad5337r_chip_info }, 107 { .compatible = "adi,ad5338r", .data = &ad5338r_chip_info }, 108 { .compatible = "adi,ad5671r", .data = &ad5672r_chip_info }, 109 { .compatible = "adi,ad5673r", .data = &ad5674r_chip_info }, 110 { .compatible = "adi,ad5675", .data = &ad5676_chip_info }, 111 { .compatible = "adi,ad5675r", .data = &ad5676r_chip_info }, 112 { .compatible = "adi,ad5677r", .data = &ad5679r_chip_info }, 113 { .compatible = "adi,ad5691r", .data = &ad5681r_chip_info }, 114 { .compatible = "adi,ad5692r", .data = &ad5682r_chip_info }, 115 { .compatible = "adi,ad5693", .data = &ad5683_chip_info }, 116 { .compatible = "adi,ad5693r", .data = &ad5683r_chip_info }, 117 { .compatible = "adi,ad5694", .data = &ad5684_chip_info }, 118 { .compatible = "adi,ad5694r", .data = &ad5684r_chip_info }, 119 { .compatible = "adi,ad5695r", .data = &ad5685r_chip_info }, 120 { .compatible = "adi,ad5696", .data = &ad5686_chip_info }, 121 { .compatible = "adi,ad5696r", .data = &ad5686r_chip_info }, 122 { .compatible = "adi,ad5697r", .data = &ad5687r_chip_info }, 123 { } 124 }; 125 MODULE_DEVICE_TABLE(of, ad5686_of_match); 126 127 static struct i2c_driver ad5686_i2c_driver = { 128 .driver = { 129 .name = "ad5696", 130 .of_match_table = ad5686_of_match, 131 }, 132 .probe = ad5686_i2c_probe, 133 .id_table = ad5686_i2c_id, 134 }; 135 136 module_i2c_driver(ad5686_i2c_driver); 137 138 MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); 139 MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); 140 MODULE_LICENSE("GPL v2"); 141 MODULE_IMPORT_NS("IIO_AD5686"); 142