#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#define AD7124_STATUS_POR_FLAG BIT(4)
/* AD7124_ADC_CONTROL */
+#define AD7124_ADC_CONTROL_CLK_SEL GENMASK(1, 0)
+#define AD7124_ADC_CONTROL_CLK_SEL_INT 0
+#define AD7124_ADC_CONTROL_CLK_SEL_INT_OUT 1
+#define AD7124_ADC_CONTROL_CLK_SEL_EXT 2
+#define AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4 3
#define AD7124_ADC_CONTROL_MODE GENMASK(5, 2)
#define AD7124_ADC_CONTROL_MODE_CONTINUOUS 0
#define AD7124_ADC_CONTROL_MODE_SINGLE 1
#define AD7124_MAX_CONFIGS 8
#define AD7124_MAX_CHANNELS 16
+#define AD7124_INT_CLK_HZ 614400
+
/* AD7124 input sources */
enum ad7124_ref_sel {
};
static const int ad7124_master_clk_freq_hz[3] = {
- [AD7124_LOW_POWER] = 76800,
- [AD7124_MID_POWER] = 153600,
- [AD7124_FULL_POWER] = 614400,
+ [AD7124_LOW_POWER] = AD7124_INT_CLK_HZ / 8,
+ [AD7124_MID_POWER] = AD7124_INT_CLK_HZ / 4,
+ [AD7124_FULL_POWER] = AD7124_INT_CLK_HZ,
};
static const char * const ad7124_ref_names[] = {
struct ad_sigma_delta sd;
struct ad7124_channel *channels;
struct regulator *vref[4];
+ u32 clk_hz;
unsigned int adc_control;
unsigned int num_channels;
struct mutex cfgs_lock; /* lock for configs access */
return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
}
+static u32 ad7124_get_fclk_hz(struct ad7124_state *st)
+{
+ enum ad7124_power_mode power_mode;
+ u32 fclk_hz;
+
+ power_mode = FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, st->adc_control);
+ fclk_hz = st->clk_hz;
+
+ switch (power_mode) {
+ case AD7124_LOW_POWER:
+ fclk_hz /= 8;
+ break;
+ case AD7124_MID_POWER:
+ fclk_hz /= 4;
+ break;
+ default:
+ break;
+ }
+
+ return fclk_hz;
+}
+
static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr)
{
unsigned int fclk, odr_sel_bits;
- fclk = ad7124_master_clk_freq_hz[FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE,
- st->adc_control)];
+ fclk = ad7124_get_fclk_hz(st);
/*
* FS[10:0] = fCLK / (fADC x 32) where:
static int ad7124_setup(struct ad7124_state *st)
{
struct device *dev = &st->sd.spi->dev;
- unsigned int power_mode;
+ unsigned int power_mode, clk_sel;
struct clk *mclk;
int i, ret;
return dev_err_probe(dev, ret,
"Failed to set mclk rate\n");
}
+
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT;
+ st->clk_hz = AD7124_INT_CLK_HZ;
+ } else {
+ struct clk *clk;
+
+ clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
+ "Failed to get external clock\n");
+
+ if (clk) {
+ unsigned long clk_hz;
+
+ clk_hz = clk_get_rate(clk);
+ if (!clk_hz)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to get external clock rate\n");
+
+ /*
+ * The external clock may be 4x the nominal clock rate,
+ * in which case the ADC needs to be configured to
+ * divide it by 4. Using MEGA is a bit arbitrary, but
+ * the expected clock rates are either 614.4 kHz or
+ * 2.4576 MHz, so this should work.
+ */
+ if (clk_hz > (1 * HZ_PER_MHZ)) {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT_DIV4;
+ st->clk_hz = clk_hz / 4;
+ } else {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_EXT;
+ st->clk_hz = clk_hz;
+ }
+ } else {
+ clk_sel = AD7124_ADC_CONTROL_CLK_SEL_INT;
+ st->clk_hz = AD7124_INT_CLK_HZ;
+ }
}
- /* Set the power mode */
+ st->adc_control &= ~AD7124_ADC_CONTROL_CLK_SEL;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_CLK_SEL, clk_sel);
+
st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode);