rk3288 adc驱动

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>;
            }
      };          

https://download.csdn.net/download/qq_37638054/11692978

你可能感兴趣的:(linux驱动)