diff options
Diffstat (limited to 'drivers/mfd/cros_ec_dev.c')
| -rw-r--r-- | drivers/mfd/cros_ec_dev.c | 235 | 
1 files changed, 12 insertions, 223 deletions
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 6e6dfd6c1871..c4b977a5dd96 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -78,6 +78,10 @@ static const struct mfd_cell cros_ec_rtc_cells[] = {  	{ .name = "cros-ec-rtc", },  }; +static const struct mfd_cell cros_ec_sensorhub_cells[] = { +	{ .name = "cros-ec-sensorhub", }, +}; +  static const struct mfd_cell cros_usbpd_charger_cells[] = {  	{ .name = "cros-usbpd-charger", },  	{ .name = "cros-usbpd-logger", }, @@ -112,229 +116,11 @@ static const struct mfd_cell cros_ec_vbc_cells[] = {  	{ .name = "cros-ec-vbc", }  }; -static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) -{ -	struct cros_ec_command *msg; -	int ret; - -	if (ec->features[0] == -1U && ec->features[1] == -1U) { -		/* features bitmap not read yet */ -		msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); -		if (!msg) -			return -ENOMEM; - -		msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset; -		msg->insize = sizeof(ec->features); - -		ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); -		if (ret < 0) { -			dev_warn(ec->dev, "cannot get EC features: %d/%d\n", -				 ret, msg->result); -			memset(ec->features, 0, sizeof(ec->features)); -		} else { -			memcpy(ec->features, msg->data, sizeof(ec->features)); -		} - -		dev_dbg(ec->dev, "EC features %08x %08x\n", -			ec->features[0], ec->features[1]); - -		kfree(msg); -	} - -	return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); -} -  static void cros_ec_class_release(struct device *dev)  {  	kfree(to_cros_ec_dev(dev));  } -static void cros_ec_sensors_register(struct cros_ec_dev *ec) -{ -	/* -	 * Issue a command to get the number of sensor reported. -	 * Build an array of sensors driver and register them all. -	 */ -	int ret, i, id, sensor_num; -	struct mfd_cell *sensor_cells; -	struct cros_ec_sensor_platform *sensor_platforms; -	int sensor_type[MOTIONSENSE_TYPE_MAX]; -	struct ec_params_motion_sense *params; -	struct ec_response_motion_sense *resp; -	struct cros_ec_command *msg; - -	msg = kzalloc(sizeof(struct cros_ec_command) + -		      max(sizeof(*params), sizeof(*resp)), GFP_KERNEL); -	if (msg == NULL) -		return; - -	msg->version = 2; -	msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; -	msg->outsize = sizeof(*params); -	msg->insize = sizeof(*resp); - -	params = (struct ec_params_motion_sense *)msg->data; -	params->cmd = MOTIONSENSE_CMD_DUMP; - -	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); -	if (ret < 0) { -		dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n", -			 ret, msg->result); -		goto error; -	} - -	resp = (struct ec_response_motion_sense *)msg->data; -	sensor_num = resp->dump.sensor_count; -	/* -	 * Allocate 2 extra sensors if lid angle sensor and/or FIFO are needed. -	 */ -	sensor_cells = kcalloc(sensor_num + 2, sizeof(struct mfd_cell), -			       GFP_KERNEL); -	if (sensor_cells == NULL) -		goto error; - -	sensor_platforms = kcalloc(sensor_num, -				   sizeof(struct cros_ec_sensor_platform), -				   GFP_KERNEL); -	if (sensor_platforms == NULL) -		goto error_platforms; - -	memset(sensor_type, 0, sizeof(sensor_type)); -	id = 0; -	for (i = 0; i < sensor_num; i++) { -		params->cmd = MOTIONSENSE_CMD_INFO; -		params->info.sensor_num = i; -		ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); -		if (ret < 0) { -			dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n", -				 i, ret, msg->result); -			continue; -		} -		switch (resp->info.type) { -		case MOTIONSENSE_TYPE_ACCEL: -			sensor_cells[id].name = "cros-ec-accel"; -			break; -		case MOTIONSENSE_TYPE_BARO: -			sensor_cells[id].name = "cros-ec-baro"; -			break; -		case MOTIONSENSE_TYPE_GYRO: -			sensor_cells[id].name = "cros-ec-gyro"; -			break; -		case MOTIONSENSE_TYPE_MAG: -			sensor_cells[id].name = "cros-ec-mag"; -			break; -		case MOTIONSENSE_TYPE_PROX: -			sensor_cells[id].name = "cros-ec-prox"; -			break; -		case MOTIONSENSE_TYPE_LIGHT: -			sensor_cells[id].name = "cros-ec-light"; -			break; -		case MOTIONSENSE_TYPE_ACTIVITY: -			sensor_cells[id].name = "cros-ec-activity"; -			break; -		default: -			dev_warn(ec->dev, "unknown type %d\n", resp->info.type); -			continue; -		} -		sensor_platforms[id].sensor_num = i; -		sensor_cells[id].id = sensor_type[resp->info.type]; -		sensor_cells[id].platform_data = &sensor_platforms[id]; -		sensor_cells[id].pdata_size = -			sizeof(struct cros_ec_sensor_platform); - -		sensor_type[resp->info.type]++; -		id++; -	} - -	if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) -		ec->has_kb_wake_angle = true; - -	if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { -		sensor_cells[id].name = "cros-ec-ring"; -		id++; -	} -	if (cros_ec_check_features(ec, -				EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) { -		sensor_cells[id].name = "cros-ec-lid-angle"; -		id++; -	} - -	ret = mfd_add_devices(ec->dev, 0, sensor_cells, id, -			      NULL, 0, NULL); -	if (ret) -		dev_err(ec->dev, "failed to add EC sensors\n"); - -	kfree(sensor_platforms); -error_platforms: -	kfree(sensor_cells); -error: -	kfree(msg); -} - -static struct cros_ec_sensor_platform sensor_platforms[] = { -	{ .sensor_num = 0 }, -	{ .sensor_num = 1 } -}; - -static const struct mfd_cell cros_ec_accel_legacy_cells[] = { -	{ -		.name = "cros-ec-accel-legacy", -		.platform_data = &sensor_platforms[0], -		.pdata_size = sizeof(struct cros_ec_sensor_platform), -	}, -	{ -		.name = "cros-ec-accel-legacy", -		.platform_data = &sensor_platforms[1], -		.pdata_size = sizeof(struct cros_ec_sensor_platform), -	} -}; - -static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec) -{ -	struct cros_ec_device *ec_dev = ec->ec_dev; -	u8 status; -	int ret; - -	/* -	 * ECs that need legacy support are the main EC, directly connected to -	 * the AP. -	 */ -	if (ec->cmd_offset != 0) -		return; - -	/* -	 * Check if EC supports direct memory reads and if EC has -	 * accelerometers. -	 */ -	if (ec_dev->cmd_readmem) { -		ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, 1, -					  &status); -		if (ret < 0) { -			dev_warn(ec->dev, "EC direct read error.\n"); -			return; -		} - -		/* Check if EC has accelerometers. */ -		if (!(status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) { -			dev_info(ec->dev, "EC does not have accelerometers.\n"); -			return; -		} -	} - -	/* -	 * The device may still support accelerometers: -	 * it would be an older ARM based device that do not suppor the -	 * EC_CMD_GET_FEATURES command. -	 * -	 * Register 2 accelerometers, we will fail in the IIO driver if there -	 * are no sensors. -	 */ -	ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells, -				      ARRAY_SIZE(cros_ec_accel_legacy_cells)); -	if (ret) -		dev_err(ec_dev->dev, "failed to add EC sensors\n"); -} -  static int ec_device_probe(struct platform_device *pdev)  {  	int retval = -ENOMEM; @@ -390,11 +176,14 @@ static int ec_device_probe(struct platform_device *pdev)  		goto failed;  	/* check whether this EC is a sensor hub. */ -	if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) -		cros_ec_sensors_register(ec); -	else -		/* Workaroud for older EC firmware */ -		cros_ec_accel_legacy_register(ec); +	if (cros_ec_get_sensor_count(ec) > 0) { +		retval = mfd_add_hotplug_devices(ec->dev, +				cros_ec_sensorhub_cells, +				ARRAY_SIZE(cros_ec_sensorhub_cells)); +		if (retval) +			dev_err(ec->dev, "failed to add %s subdevice: %d\n", +				cros_ec_sensorhub_cells->name, retval); +	}  	/*  	 * The following subdevices can be detected by sending the  |