adc现在使用了iio子系统,文件位置位于driver/iio/adc/rockchip_adc.c
设备树文件、
adc: adc@ff100000 {
compatible = "rockchip,saradc";
reg = <0xff100000 0x100>;
interrupts = ;
#io-channel-cells = <1>;
io-channel-ranges;
rockchip,adc-vref = <1800>;
clock-frequency = <1000000>;
clocks = <&clk_saradc>, <&clk_gates7 1>;
clock-names = "saradc", "pclk_saradc";
status = "disabled";
};
static struct platform_driver rk_adc_driver = {
.probe = rk_adc_probe,
.remove = rk_adc_remove,
.driver = {
.name = "rockchip-adc",
.owner = THIS_MODULE,
.of_match_table = rk_adc_match,
.pm = &rk_adc_pm_ops,
},
};
module_platform_driver(rk_adc_driver);
首先内核注册一个平台驱动,那么就要有一个平台设备与之相匹配才会调用它的probe函数。通过compatible属性来匹配。
static const struct of_device_id rk_adc_match[] = {
{ .compatible = "rockchip,saradc", .data = NULL},
{},
};
rk_adc_probe分析:
static const struct iio_info rk_adc_iio_info = {
.read_raw = &rk_read_raw, //读取adc数据
.debugfs_reg_access = &rk_adc_reg_access, //用来访问寄存器
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec rk_adc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
ADC_CHANNEL(6, "adc6"),
};
rk_adc_probe
struct rk_adc *info = NULL; //自定义结构体,用来记录一些资源,还有一个完成量。
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
indio_dev = iio_device_alloc(sizeof(struct rk_adc)); //分配一个iio_dev结构体,作为一个工业io设备。
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取reg的地址
info->regs = devm_request_and_ioremap(&pdev->dev, mem); //映射到内核空间
irq = platform_get_irq(pdev, 0); //得到中断号
info->irq = irq;
init_completion(&info->completion);
ret = devm_request_irq(&pdev->dev, info->irq, rk_adc_isr, 0, dev_name(&pdev->dev), info);
info->pclk = devm_clk_get(&pdev->dev, "pclk_saradc");
of_property_read_u32(np, "clock-frequency", &rate); //得到时钟频率
ret = clk_set_rate(info->clk, rate); // 设置时钟频率
clk_prepare(info->clk);
//device register
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &rk_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = rk_adc_iio_channels;
of_property_read_u32(np, "rockchip,adc-vref", &info->vref_mv); //获取adc的参考电压1.8v
indio_dev->num_channels = sizeof(rk_adc_iio_channels)/sizeof(struct iio_chan_spec); // 记录通道数
ret = iio_device_register(indio_dev); // 向内核注册iio_dev
platform_set_drvdata(pdev, indio_dev); // 把iio_dev放到平台设备的私有数据里
ret = of_platform_populate(np, rk_adc_match, NULL, &pdev->dev); //在其下的子节点种创建platform_device结构体。
添加adc下面的设备。
&adc {
status = "okay";
key {
compatible = "rockchip,key";
io-channels = <&adc 1>;
/*
vol-up-key {
linux,code = <115>;
label = "volume up";
rockchip,adc_value = <1>;
};
vol-down-key {
linux,code = <114>;
label = "volume down";
rockchip,adc_value = <170>;
};
*/
power-key {
gpios = <&gpio0 GPIO_A5 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
gpio-key,wakeup;
};
recovery-key {
linux,code = <113>;
label = "recovery";
rockchip,adc_value = <4>;
};
/*
menu-key {
linux,code = <59>;
label = "menu";
rockchip,adc_value = <355>;
};
home-key {
linux,code = <102>;
label = "home";
rockchip,adc_value = <746>;
};
back-key {
linux,code = <158>;
label = "back";
rockchip,adc_value = <560>;
};
camera-key {
linux,code = <212>;
label = "camera";
rockchip,adc_value = <450>;
};*/
};
};
drivers/input/keyboard/rk_keys.c
//临时笔记
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
}
};
struct rk_keys_drvdata {
int nbuttons;
/* flag to indicate if we’re suspending/resuming */
bool in_suspend;
int result;
int rep;
struct wake_lock wake_lock;
struct input_dev *input;
struct delayed_work adc_poll_work;
struct iio_channel *chan;
struct rk_keys_button button[0];
};
module_platform_driver(keys_device_driver); //注册了一个平台drv
keys_probe -->
struct rk_keys_drvdata *ddata = NULL;
key_num = of_get_child_count(np); // 得到其下的子节点数,也就是按键数
input = devm_input_allocate_device(dev);//分配一个input_dev
platform_set_drvdata(pdev, ddata);//把设备自定结构体放到平台的私有数据里
input->name = “rk29-keypad”; /* pdev->name; */
input->phys = “gpio-keys/input0”;
input->dev.parent = dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
error = rk_keys_parse_dt(ddata, pdev); // 解析设备树,获取通道号,记录每一个按键的"linux,code"
//对于每个按键指定能产生按键类事件
for (i = 0; i < ddata->nbuttons; i++) {
struct rk_keys_button *button = &ddata->button[i];
if (button->code) {
setup_timer(&button->timer,
keys_timer, (unsigned long)button);
}
if (button->wakeup)
wakeup = 1;
input_set_capability(input, EV_KEY, button->code);
}
//设置能产生按键类事件的哪种事件
//设置按键的gpio口为输入
input_register_device(input);//将input_dev注册进内核
iio_channel_get -->
of_iio_channel_get_by_name(dev->of_node, channel_name);
chan = of_iio_channel_get(np, index);
__of_iio_channel_get(channel, np, index);
of_parse_phandle_with_args(np, “io-channels”, “#io-channel-cells”, index, &iiospec);
__of_parse_phandle_with_args(np, list_name, cells_name, 0, index, out_args);
list = of_get_property(np, list_name, &size);
实验:添加一个设备,使用adc0,外接一个5k,10k,20k电阻作测试
在其他驱动使用时:
1、首先获取adc的通道
struct iio_channel *iio_channel_get(struct device *dev, const char *channel_name)
2、获取adc的原始数据。
int iio_read_channel_raw(struct iio_channel *chan, int *val)
模仿"rockchip,key" 添加设备树:
&adc {
status = "okay";
tmp-sensor {
compatible = "rockchip,tmperature";
io-channels = <&adc 0>;
}
};
原作者:风见暗含
|