RK3399开发板上的 AD 接口有两种,分别为:温度传感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Register)。
SAR-ADC 的 DTS 节点在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 文件中定义,如下所示:
saradc: saradc@ff100000 {
compatible = "rockchip,rk3399-saradc";
reg = <0x0 0xff100000 0x0 0x100>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH 0>;
#io-channel-cells = <1>;
clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
clock-names = "saradc", "apb_pclk";
resets = <&cru SRST_P_SARADC>;
reset-names = "saradc-apb";
status = "disabled";
};
用户首先需在DTS文件中添加ADC的资源描述:
&rk_key {
compatible = "rockchip,key";
status = "okay";
io-channels = <&saradc 1>;
vol-up-key {
linux,code = <114>;
label = "volume up";
rockchip,adc_value = <1>;
};
vol-down-key {
linux,code = <115>;
label = "volume down";
rockchip,adc_value = <170>;
};
power-key {
gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
gpio-key,wakeup;
};
menu-key {
linux,code = <59>;
label = "menu";
rockchip,adc_value = <746>;
};
home-key {
linux,code = <102>;
label = "home";
rockchip,adc_value = <355>;
};
back-key {
linux,code = <158>;
label = "back";
rockchip,adc_value = <560>;
};
camera-key {
linux,code = <212>;
label = "camera";
rockchip,adc_value = <450>;
};
};
这里申请的是SARADC通道1
驱动key:drivers/input/keyboard/rk_keys.c
首先在驱动文件中定义 of_device_id 结构体数组:
static const struct of_device_id rk_key_match[] = {
{ .compatible = "rockchip,key", .data = NULL},
{},
};
然后将该结构体数组填充到 platform_driver 中:
static struct platform_driver keys_device_driver = {
.probe = keys_probe,
.remove = keys_remove,
.driver = {
.name = "rk-keypad",
.owner = THIS_MODULE,
.of_match_table = rk_key_match,
#ifdef CONFIG_PM
.pm = &keys_pm_ops,
#endif
}
};
接着在keys_probe中使用work 进行polling :
/* adc polling work */
if (ddata->chan) {
INIT_DELAYED_WORK(&ddata->adc_poll_work, adc_key_poll);
schedule_delayed_work(&ddata->adc_poll_work,
┊ ┊ ADC_SAMPLE_JIFFIES);
}
ADC key Poll DTS资源解析
static void adc_key_poll(struct work_struct *work)
{
struct rk_keys_drvdata *ddata;
int i, result = -1;
ddata = container_of(work, struct rk_keys_drvdata, adc_poll_work.work);
if (!ddata->in_suspend) {
result = rk_key_adc_iio_read(ddata);/**读取SARADC值*/
if (result > INVALID_ADVALUE &&
┊ result < (EMPTY_DEFAULT_ADVALUE - ddata->drift_advalue))
ddata->result = result;
for (i = 0; i < ddata->nbuttons; i++) {
struct rk_keys_button *button = &ddata->button[i];
if (!button->adc_value)
continue;
if (result < button->adc_value + ddata->drift_advalue &&
┊ result > button->adc_value - ddata->drift_advalue)
button->adc_state = 1;
else
button->adc_state = 0;
if (button->state != button->adc_state)
mod_timer(&button->timer,
┊ jiffies + DEBOUNCE_JIFFIES);
}
}
schedule_delayed_work(&ddata->adc_poll_work, ADC_SAMPLE_JIFFIES);
}
在解析资源DTS时 获取对应的通道
struct iio_channel *chan; /定义 IIO 通道结构体
chan = iio_channel_get(&pdev->dev, NULL); /获取 IIO 通道结构体/
static int rk_keys_parse_dt(struct rk_keys_drvdata *pdata,struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device_node *child_node;
struct iio_channel *chan;
int ret, gpio, i = 0;
u32 code, adc_value, flags, drift;
if (of_property_read_u32(node, "adc-drift", &drift))
pdata->drift_advalue = DRIFT_DEFAULT_ADVALUE;
else
pdata->drift_advalue = (int)drift;
chan = iio_channel_get(&pdev->dev, NULL);
...............
在adc_key polling中 调用 iio_read_channel_raw 函数读取 AD 采集的原始数据并存入 val 中
ret = iio_read_channel_raw(channel, &val);
Vref / (2^n-1) = Vresult / raw
注:
Vref 为标准电压
n 为 AD 转换的位数
Vresult 为用户所需要的采集电压
raw 为 AD 采集的原始数据
struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel);
void iio_channel_release(struct iio_channel *chan);
int iio_read_channel_raw(struct iio_channel *chan, int *val);
cat /sys/bus/iio/devices/iio\:device1/in_voltage*_raw
876
1021
164
512
513
349