linux驱动(第二十四课 PWM)

PWMDEV是一个典型的CDEV。
内核实现了PWMCORE,向上提供一个CDEV的用户接口,向下,调用不同的PWMCONTROLLER提供服务。

类似于GPIOCHIP,在kernel中,PWMCHIP就是用来控制PWMCONTROLLER的一个结构体。

struct pwm_chip{
	struct device* dev;
	const struct pwm_ops* ops;
	int base;
	unsigned int npwm;
	struct pwm_device* pwms;
	...
};

内核提供了PWM相关的API,

int pwmchip_add(struct pwm_chip* chip);
int pwmchip_remove(struct pwm_chip* chip);

PWMOPS是底层驱动的操作集,这是PWM的具体驱动需要实现的函数集。

struct pwm_ops{
	int (*request)(struct pwm_chip* chip, struct pwm_device* pwm);
	int (*free)(struct pwm_chip* chip, struct pwm_device* pwm);
	int (*enable)(struct pwm_chip* chip, struct pwm_device* pwm);
	int (*disable)(struct pwm_chip* chip, struct pwm_device* pwm);
	int (*config)(struct pwm_chip* chip, struct pwm_device* pwm, int duty, int period);
	...
};

这样,内核对PWMCTRL的管理,就转化成注册一个pwm_chip的问题。
如果DerivedPWMCHIP,同时实现为一个platform device。那么可以在probe中,只需要创建一个DerivedPWMCHIP,填充好后,将PWMCHIP利用pwmchip_add内核服务注册到内核中。
类似于CDEV,我们需要实例化pwm_ops,并编写具体函数。
由于使用了DerivedDEV,所以要配置好private_data。
例如:

struct fake_chip{
	struct pwm_chip
	int foo;
	int bar;
	...
};


static int fake_pwm_probe(struct platform_device* pdev)
{
	struct fake_chip* priv;
	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);

	priv->chip.ops = &fake_pwm_ops;
	priv->chip.dev = &pdev->dev;
	...

	platform_set_drv_data(pdev, priv);
	ret = pwmchip_add(&priv->chip);

	return ret;
}

从中可以看出,利用DEVICE对象,即pdev->dev句柄,创建了对应的DerivedDEV。
然后填充了PWMOPS。配置了PWMCHIP关联的DEVICE对象。
然后将创建的PWMCHIP的句柄,配置到drvdata中,建立回溯引用。
最后,将PWMCHIP注册到了内核中。

另外一个结构体就是pwm_device,这是用户程序需要使用的结构体。

struct pwm_device{
	const char* name;
	unsigned int hwpwm;
	unsigned int pwm;
	unsigned long flags;

	struct pwm_args args;
	struct pwm_state state;
	
	struct pwm_chip* chip;
	void* chip_data;
	...
};

struct pwm_args{
	unsigned int period;
	...
};

struct pwm_state{
	unsigned int period;
	unsigned int duty_cycle;
	bool enabled;
	...

};

PWMDEV关联到一个PWMCHIP,所以,一个PWMDEV,是利用PWMCHIP完成的具体操作任务。

用户程序使用内核提供的API来操作pwm_device。

struct pwm_device* pwm_get(struct device* dev, const char* con_id);
struct pwm_device* pwm_put(struct pwm_device* pwm);
int pwm_config(struct pwm_device* pwm, int duty, int period);
int pwm_enable(struct pwm_device* pwm);
void pwm_disable(struct pwm_device* pwm);

驱动设计时,我们需要在probe中,向内核注册PWMDEV,即,利用pwm_get来完成注册。

你可能感兴趣的:(driver)