18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5592R Digital <-> Analog converters driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2015-2016 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * Author: Paul Cercueil <paul.cercueil@analog.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ad5592r-base.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define AD5592R_GPIO_READBACK_EN BIT(10) 178c2ecf20Sopenharmony_ci#define AD5592R_LDAC_READBACK_EN BIT(6) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int ad5592r_spi_wnop_r16(struct ad5592r_state *st, __be16 *buf) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct spi_device *spi = container_of(st->dev, struct spi_device, dev); 228c2ecf20Sopenharmony_ci struct spi_transfer t = { 238c2ecf20Sopenharmony_ci .tx_buf = &st->spi_msg_nop, 248c2ecf20Sopenharmony_ci .rx_buf = buf, 258c2ecf20Sopenharmony_ci .len = 2 268c2ecf20Sopenharmony_ci }; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci st->spi_msg_nop = 0; /* NOP */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return spi_sync_transfer(spi, &t, 1); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int ad5592r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct spi_device *spi = container_of(st->dev, struct spi_device, dev); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci st->spi_msg = cpu_to_be16(BIT(15) | (chan << 12) | value); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg)); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int ad5592r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct spi_device *spi = container_of(st->dev, struct spi_device, dev); 458c2ecf20Sopenharmony_ci int ret; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci st->spi_msg = cpu_to_be16((AD5592R_REG_ADC_SEQ << 11) | BIT(chan)); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg)); 508c2ecf20Sopenharmony_ci if (ret) 518c2ecf20Sopenharmony_ci return ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * Invalid data: 558c2ecf20Sopenharmony_ci * See Figure 40. Single-Channel ADC Conversion Sequence 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci ret = ad5592r_spi_wnop_r16(st, &st->spi_msg); 588c2ecf20Sopenharmony_ci if (ret) 598c2ecf20Sopenharmony_ci return ret; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci ret = ad5592r_spi_wnop_r16(st, &st->spi_msg); 628c2ecf20Sopenharmony_ci if (ret) 638c2ecf20Sopenharmony_ci return ret; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci *value = be16_to_cpu(st->spi_msg); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int ad5592r_reg_write(struct ad5592r_state *st, u8 reg, u16 value) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct spi_device *spi = container_of(st->dev, struct spi_device, dev); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci st->spi_msg = cpu_to_be16((reg << 11) | value); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct spi_device *spi = container_of(st->dev, struct spi_device, dev); 828c2ecf20Sopenharmony_ci int ret; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci st->spi_msg = cpu_to_be16((AD5592R_REG_LDAC << 11) | 858c2ecf20Sopenharmony_ci AD5592R_LDAC_READBACK_EN | (reg << 2)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg)); 888c2ecf20Sopenharmony_ci if (ret) 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = ad5592r_spi_wnop_r16(st, &st->spi_msg); 928c2ecf20Sopenharmony_ci if (ret) 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci *value = be16_to_cpu(st->spi_msg); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int ad5592r_gpio_read(struct ad5592r_state *st, u8 *value) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int ret; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ret = ad5592r_reg_write(st, AD5592R_REG_GPIO_IN_EN, 1058c2ecf20Sopenharmony_ci AD5592R_GPIO_READBACK_EN | st->gpio_in); 1068c2ecf20Sopenharmony_ci if (ret) 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci ret = ad5592r_spi_wnop_r16(st, &st->spi_msg); 1108c2ecf20Sopenharmony_ci if (ret) 1118c2ecf20Sopenharmony_ci return ret; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci *value = (u8) be16_to_cpu(st->spi_msg); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const struct ad5592r_rw_ops ad5592r_rw_ops = { 1198c2ecf20Sopenharmony_ci .write_dac = ad5592r_write_dac, 1208c2ecf20Sopenharmony_ci .read_adc = ad5592r_read_adc, 1218c2ecf20Sopenharmony_ci .reg_write = ad5592r_reg_write, 1228c2ecf20Sopenharmony_ci .reg_read = ad5592r_reg_read, 1238c2ecf20Sopenharmony_ci .gpio_read = ad5592r_gpio_read, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int ad5592r_spi_probe(struct spi_device *spi) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int ad5592r_spi_remove(struct spi_device *spi) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci return ad5592r_remove(&spi->dev); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic const struct spi_device_id ad5592r_spi_ids[] = { 1398c2ecf20Sopenharmony_ci { .name = "ad5592r", }, 1408c2ecf20Sopenharmony_ci {} 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad5592r_spi_ids); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic const struct of_device_id ad5592r_of_match[] = { 1458c2ecf20Sopenharmony_ci { .compatible = "adi,ad5592r", }, 1468c2ecf20Sopenharmony_ci {}, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ad5592r_of_match); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct acpi_device_id ad5592r_acpi_match[] = { 1518c2ecf20Sopenharmony_ci {"ADS5592", }, 1528c2ecf20Sopenharmony_ci { }, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, ad5592r_acpi_match); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct spi_driver ad5592r_spi_driver = { 1578c2ecf20Sopenharmony_ci .driver = { 1588c2ecf20Sopenharmony_ci .name = "ad5592r", 1598c2ecf20Sopenharmony_ci .of_match_table = ad5592r_of_match, 1608c2ecf20Sopenharmony_ci .acpi_match_table = ad5592r_acpi_match, 1618c2ecf20Sopenharmony_ci }, 1628c2ecf20Sopenharmony_ci .probe = ad5592r_spi_probe, 1638c2ecf20Sopenharmony_ci .remove = ad5592r_spi_remove, 1648c2ecf20Sopenharmony_ci .id_table = ad5592r_spi_ids, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_cimodule_spi_driver(ad5592r_spi_driver); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>"); 1698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); 1708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 171