[RK3288-Android8.1]cw2015驱动调试曲折

Android8.1使用的是kernel4.4,驱动中自带的cw2015没有dc_det功能,因此需要将之前Android6.0,kernel3.1中使用的cw2015驱动尝试移植到8.1中。

代码拷贝过来后果然很多报错。编译过程中,包括rk_bat,rk_ac,rk_usb均会报错power_supply 没有成员 type,properties等

 

static int cw_bat_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
中,cw_bat->rk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
	cw_bat->rk_bat.properties = rk_battery_properties;
	cw_bat->rk_bat.num_properties = ARRAY_SIZE(rk_battery_properties);
	cw_bat->rk_bat.get_property = rk_battery_get_property;
	ret = power_supply_register(&client->dev, &cw_bat->rk_bat);

很显然是内核的接口变了, 查看include/linux/power_supply.h中struct power_supply的定义:

struct power_supply {
	const struct power_supply_desc *desc;

	char **supplied_to;
	size_t num_supplicants;

	char **supplied_from;
	size_t num_supplies;
	struct device_node *of_node;

	/* Driver private data */
	void *drv_data;

	/* private */
	struct device dev;
	struct work_struct changed_work;
	struct delayed_work deferred_register_work;
	spinlock_t changed_lock;
	bool changed;
	bool initialized;
	atomic_t use_cnt;
#ifdef CONFIG_THERMAL
	struct thermal_zone_device *tzd;
	struct thermal_cooling_device *tcd;
#endif

#ifdef CONFIG_LEDS_TRIGGERS
	struct led_trigger *charging_full_trig;
	char *charging_full_trig_name;
	struct led_trigger *charging_trig;
	char *charging_trig_name;
	struct led_trigger *full_trig;
	char *full_trig_name;
	struct led_trigger *online_trig;
	char *online_trig_name;
	struct led_trigger *charging_blink_full_solid_trig;
	char *charging_blink_full_solid_trig_name;
#endif
};

的确是没有这些成员了,不过看一眼便知,这些成员都封装在power_supply_desc 这个结构体中:

struct power_supply_desc {
	const char *name;
	enum power_supply_type type;
	enum power_supply_property *properties;
	size_t num_properties;

	/*
	 * Functions for drivers implementing power supply class.
	 * These shouldn't be called directly by other drivers for accessing
	 * this power supply. Instead use power_supply_*() functions (for
	 * example power_supply_get_property()).
	 */
	int (*get_property)(struct power_supply *psy,
			    enum power_supply_property psp,
			    union power_supply_propval *val);
	int (*set_property)(struct power_supply *psy,
			    enum power_supply_property psp,
			    const union power_supply_propval *val);
	/*
	 * property_is_writeable() will be called during registration
	 * of power supply. If this happens during device probe then it must
	 * not access internal data of device (because probe did not end).
	 */
	int (*property_is_writeable)(struct power_supply *psy,
				     enum power_supply_property psp);
	void (*external_power_changed)(struct power_supply *psy);
	void (*set_charged)(struct power_supply *psy);

	/*
	 * Set if thermal zone should not be created for this power supply.
	 * For example for virtual supplies forwarding calls to actual
	 * sensors or other supplies.
	 */
	bool no_thermal;
	/* For APM emulation, think legacy userspace. */
	int use_for_apm;
};

如此来看,只需要在代码中多加一个指向成员就可以了吗?然而这个desc在power_supply中是const的,如此修改编译器只会告诉你desc是只读的,不允许定义后修改,那么只剩下一种方案了,就是在power_supply初始化之后,
定义一个power_supply_desc指针,将需要初始化的内容填充好,然后把这个指针传给power_supply中的desc。这种方法还有两种方案,一种是在初始化的过程中动态的去申请和传递,另一种是在初始化之前,直接静态定义好
接口,初始化之后直接传递,后者写起来比较方便,但是直接定义静态的const数据不太好,还是动态申请吧:

struct power_supply_desc *rk_bat_desc;
rk_bat_desc = devm_kzalloc(&client->dev, sizeof(*rk_bat_desc), GFP_KERNEL);
	if (!rk_bat_desc)
		return -ENOMEM;
	
	rk_bat_desc->name = "rk-bat";
	rk_bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
	rk_bat_desc->properties = rk_battery_properties;
	rk_bat_desc->num_properties = ARRAY_SIZE(rk_battery_properties);
	rk_bat_desc->get_property = rk_battery_get_property;

其中,注册的接口也变化了:

extern struct power_supply *__must_check
power_supply_register(struct device *parent,
				 const struct power_supply_desc *desc,
				 const struct power_supply_config *cfg);

第二个参数接受的是 power_supply_desc, 第三个这是power_supply_config,所以还需要构建一个cfg指针,cfg需要接受一个device作为 drv_data,

struct power_supply_config psy_cfg = { .drv_data = cw_bat, };

同时返回一个 struct power_supply, 旧接口返回的是一个int错误码,可以判断是否注册成功,新的接口可以把返回值赋给cw_bat->rk_bat:

cw_bat->rk_bat = power_supply_register(&client->dev, rk_bat_desc, &psy_cfg);

后,在这个函数中,还会报错: get_gadget_connect_flag()未定义,也是新内核中usb的接口变化了,搜一下代码发现这个方法只用于初始化一个值,直接替换成0即可。

static int get_usb_charge_state(struct cw_battery *cw_bat)
{
	int charge_time;
	int time_from_boot;
	struct timespec ts;

	int gadget_status = get_gadget_connect_flag();
	int usb_status = dwc_vbus_status();

	get_monotonic_boottime(&ts);
	time_from_boot = ts.tv_sec;

	if (cw_bat->charger_init_mode) {
		if (usb_status == 1 || usb_status == 2) {
			cw_bat->charger_init_mode = 0;
		} else if (time_from_boot < 8) {
			usb_status = cw_bat->charger_init_mode;
		} else if (strstr(saved_command_line, "charger")) {
			cw_bat->charger_init_mode = dwc_otg_check_dpdm();
			usb_status = cw_bat->charger_init_mode;
		}
	}
#ifdef NO_STANDARD_AC_BIG_CHARGE_MODE
	if (cw_bat->usb_online == 1) {
		charge_time =
		    time_from_boot - cw_bat->sleep_time_charge_start -
		    cw_bat->run_time_charge_start;
		if (charge_time > 3) {
			if (gadget_status == 0 && dwc_vbus_status() == 1)
				usb_status = 2;
		}
	}
#endif

	dev_dbg(&cw_bat->client->dev,
		"%s usb_status=[%d],cw_bat->charger_mode=[%d],cw_bat->gadget_status=[%d], cw_bat->charger_init_mode = [%d]\n",
		__func__, usb_status, cw_bat->charger_mode, gadget_status,
		cw_bat->charger_init_mode);

	return usb_status;
}

再次编译,成功通过。

你可能感兴趣的:([RK3288-Android8.1]cw2015驱动调试曲折)