--- /dev/null
+/****************************************************************************
+ * extdrv/mcp3021_adc_i2c.c
+ *
+ *
+ * Copyright 2021 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "core/system.h"
+#include "lib/errno.h"
+#include "lib/utils.h"
+#include "drivers/i2c.h"
+#include "extdrv/mcp3021_adc_i2c.h"
+
+
+/***************************************************************************** */
+/* Support for MCP3021 I2C ADC from Microchip */
+/***************************************************************************** */
+
+/* The MCP3021 has no internal registers.
+ * Data sampling is triggered by reading from the device
+ * (triggering occurs on the R/W bit of the address byte set to Read)
+ * Continuous sampling is triggered by continuous reading.
+ * Samples are received on two contiguous bytes, with the four upper bits on the
+ * four lower bits of the first byte and the six lower bits on the six upper
+ * bits of the second byte.
+ */
+
+
+/* Check the sensor presence, return 1 if sensor was found.
+ * This is a basic check, it could be anything with the same address ...
+ * This check can be made either by trying to write nothing, or by reading a sample.
+ */
+int mcp3021_probe(struct mcp3021_config* conf)
+{
+ char cmd_buf = (conf->addr | I2C_WRITE_BIT);
+
+ /* Did we already probe the sensor ? */
+ if (conf->probe_ok != 1) {
+ conf->probe_ok = i2c_write(conf->bus_num, &cmd_buf, 1, NULL);
+ }
+ return conf->probe_ok;
+}
+
+/* ADC Read
+ * Read _len_ samples from the ADC, put the shifted samples into _values_
+ * Return value(s):
+ * Upon successfull completion, returns the number of samples read.
+ * On error, returns a negative integer equivalent to errors from glibc.
+ */
+#define CMD_BUF_SIZE 1
+int mcp3021_read(struct mcp3021_config* conf, uint16_t* values, int len)
+{
+ int ret = 0, i = 0;
+ char cmd_buf[CMD_BUF_SIZE] = { (conf->addr | I2C_READ_BIT), };
+ char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, };
+
+ if (mcp3021_probe(conf) != 1) {
+ return -ENODEV;
+ }
+ if (values == NULL) {
+ return -EINVAL;
+ }
+
+ /* Read the requested data */
+ ret = i2c_read(conf->bus_num, cmd_buf, CMD_BUF_SIZE, ctrl_buf, (char*)values, (len * 2));
+
+ if (ret != (len * 2)) {
+ conf->probe_ok = 0;
+ return ret;
+ }
+
+ /* Shift all values */
+ for (i = 0; i < len; i++) {
+ values[i] = ntohs(values[i]) >> 2;
+ }
+ return len;
+}
+
+int mcp3021_config(struct mcp3021_config* conf)
+{
+ if (mcp3021_probe(conf) != 1) {
+ return -ENODEV;
+ }
+ return 0; /* Config success */
+}
+
+
--- /dev/null
+/****************************************************************************
+ * extdrv/mcp3021_adc_i2c.h
+ *
+ *
+ * Copyright 2021 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef MCP3021_ADC_H
+#define MCP3021_ADC_H
+
+
+/***************************************************************************** */
+/* Support for MCP3021 I2C ADC from Microchip */
+/***************************************************************************** */
+
+/* The MCP3021 has no internal registers.
+ * Data sampling is triggered by reading from the device
+ * (triggering occurs on the R/W bit of the address byte set to Read)
+ * Continuous sampling is triggered by continuous reading.
+ * Samples are received on two contiguous bytes, with the four upper bits on the
+ * four lower bits of the first byte and the six lower bits on the six upper
+ * bits of the second byte.
+ */
+
+struct mcp3021_config {
+ uint8_t bus_num;
+ uint8_t addr;
+ uint8_t probe_ok;
+};
+
+/* ADC Read
+ * Read _len_ samples from the ADC, put the shifted samples into _values_
+ * Return value(s):
+ * Upon successfull completion, returns the number of samples read.
+ * On error, returns a negative integer equivalent to errors from glibc.
+ */
+int mcp3021_read(struct mcp3021_config* conf, uint16_t* values, int len);
+
+int mcp3021_config(struct mcp3021_config* conf);
+
+
+#endif /* MCP3021_ADC_H */
+