diff options
Diffstat (limited to 'drivers/i2c/i2c-core-base.c')
| -rw-r--r-- | drivers/i2c/i2c-core-base.c | 121 | 
1 files changed, 89 insertions, 32 deletions
| diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 63ebf722a424..5a97e4a02fa2 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -76,6 +76,27 @@ void i2c_transfer_trace_unreg(void)  	static_branch_dec(&i2c_trace_msg_key);  } +const char *i2c_freq_mode_string(u32 bus_freq_hz) +{ +	switch (bus_freq_hz) { +	case I2C_MAX_STANDARD_MODE_FREQ: +		return "Standard Mode (100 kHz)"; +	case I2C_MAX_FAST_MODE_FREQ: +		return "Fast Mode (400 kHz)"; +	case I2C_MAX_FAST_MODE_PLUS_FREQ: +		return "Fast Mode Plus (1.0 MHz)"; +	case I2C_MAX_TURBO_MODE_FREQ: +		return "Turbo Mode (1.4 MHz)"; +	case I2C_MAX_HIGH_SPEED_MODE_FREQ: +		return "High Speed Mode (3.4 MHz)"; +	case I2C_MAX_ULTRA_FAST_MODE_FREQ: +		return "Ultra Fast Mode (5.0 MHz)"; +	default: +		return "Unknown Mode"; +	} +} +EXPORT_SYMBOL_GPL(i2c_freq_mode_string); +  const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,  						const struct i2c_client *client)  { @@ -249,7 +270,7 @@ EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);  int i2c_recover_bus(struct i2c_adapter *adap)  {  	if (!adap->bus_recovery_info) -		return -EOPNOTSUPP; +		return -EBUSY;  	dev_dbg(&adap->dev, "Trying i2c bus recovery\n");  	return adap->bus_recovery_info->recover_bus(adap); @@ -378,7 +399,7 @@ static int i2c_gpio_init_recovery(struct i2c_adapter *adap)  static int i2c_init_recovery(struct i2c_adapter *adap)  {  	struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; -	char *err_str; +	char *err_str, *err_level = KERN_ERR;  	if (!bri)  		return 0; @@ -387,7 +408,8 @@ static int i2c_init_recovery(struct i2c_adapter *adap)  		return -EPROBE_DEFER;  	if (!bri->recover_bus) { -		err_str = "no recover_bus() found"; +		err_str = "no suitable method provided"; +		err_level = KERN_DEBUG;  		goto err;  	} @@ -414,7 +436,7 @@ static int i2c_init_recovery(struct i2c_adapter *adap)  	return 0;   err: -	dev_err(&adap->dev, "Not using recovery: %s\n", err_str); +	dev_printk(err_level, &adap->dev, "Not using recovery: %s\n", err_str);  	adap->bus_recovery_info = NULL;  	return -EINVAL; @@ -518,6 +540,13 @@ static int i2c_device_probe(struct device *dev)  	if (status)  		goto err_clear_wakeup_irq; +	client->devres_group_id = devres_open_group(&client->dev, NULL, +						    GFP_KERNEL); +	if (!client->devres_group_id) { +		status = -ENOMEM; +		goto err_detach_pm_domain; +	} +  	/*  	 * When there are no more users of probe(),  	 * rename probe_new to probe. @@ -530,11 +559,21 @@ static int i2c_device_probe(struct device *dev)  	else  		status = -EINVAL; +	/* +	 * Note that we are not closing the devres group opened above so +	 * even resources that were attached to the device after probe is +	 * run are released when i2c_device_remove() is executed. This is +	 * needed as some drivers would allocate additional resources, +	 * for example when updating firmware. +	 */ +  	if (status) -		goto err_detach_pm_domain; +		goto err_release_driver_resources;  	return 0; +err_release_driver_resources: +	devres_release_group(&client->dev, client->devres_group_id);  err_detach_pm_domain:  	dev_pm_domain_detach(&client->dev, true);  err_clear_wakeup_irq: @@ -563,6 +602,8 @@ static int i2c_device_remove(struct device *dev)  			dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status));  	} +	devres_release_group(&client->dev, client->devres_group_id); +  	dev_pm_domain_detach(&client->dev, true);  	dev_pm_clear_wake_irq(&client->dev); @@ -611,7 +652,7 @@ modalias_show(struct device *dev, struct device_attribute *attr, char *buf)  	if (len != -ENODEV)  		return len; -	len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); +	len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);  	if (len != -ENODEV)  		return len; @@ -909,11 +950,11 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf  	i2c_dev_set_name(adap, client, info); -	if (info->properties) { -		status = device_add_properties(&client->dev, info->properties); +	if (info->swnode) { +		status = device_add_software_node(&client->dev, info->swnode);  		if (status) {  			dev_err(&adap->dev, -				"Failed to add properties to client %s: %d\n", +				"Failed to add software node to client %s: %d\n",  				client->name, status);  			goto out_err_put_of_node;  		} @@ -921,16 +962,15 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf  	status = device_register(&client->dev);  	if (status) -		goto out_free_props; +		goto out_remove_swnode;  	dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",  		client->name, dev_name(&client->dev));  	return client; -out_free_props: -	if (info->properties) -		device_remove_properties(&client->dev); +out_remove_swnode: +	device_remove_software_node(&client->dev);  out_err_put_of_node:  	of_node_put(info->of_node);  out_err: @@ -960,6 +1000,7 @@ void i2c_unregister_device(struct i2c_client *client)  	if (ACPI_COMPANION(&client->dev))  		acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); +	device_remove_software_node(&client->dev);  	device_unregister(&client->dev);  }  EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1016,15 +1057,9 @@ struct i2c_client *i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address  }  EXPORT_SYMBOL_GPL(i2c_new_dummy_device); -struct i2c_dummy_devres { -	struct i2c_client *client; -}; - -static void devm_i2c_release_dummy(struct device *dev, void *res) +static void devm_i2c_release_dummy(void *client)  { -	struct i2c_dummy_devres *this = res; - -	i2c_unregister_device(this->client); +	i2c_unregister_device(client);  }  /** @@ -1041,20 +1076,16 @@ struct i2c_client *devm_i2c_new_dummy_device(struct device *dev,  					     struct i2c_adapter *adapter,  					     u16 address)  { -	struct i2c_dummy_devres *dr;  	struct i2c_client *client; - -	dr = devres_alloc(devm_i2c_release_dummy, sizeof(*dr), GFP_KERNEL); -	if (!dr) -		return ERR_PTR(-ENOMEM); +	int ret;  	client = i2c_new_dummy_device(adapter, address); -	if (IS_ERR(client)) { -		devres_free(dr); -	} else { -		dr->client = client; -		devres_add(dev, dr); -	} +	if (IS_ERR(client)) +		return client; + +	ret = devm_add_action_or_reset(dev, devm_i2c_release_dummy, client); +	if (ret) +		return ERR_PTR(ret);  	return client;  } @@ -1703,6 +1734,32 @@ void i2c_del_adapter(struct i2c_adapter *adap)  }  EXPORT_SYMBOL(i2c_del_adapter); +static void devm_i2c_del_adapter(void *adapter) +{ +	i2c_del_adapter(adapter); +} + +/** + * devm_i2c_add_adapter - device-managed variant of i2c_add_adapter() + * @dev: managing device for adding this I2C adapter + * @adapter: the adapter to add + * Context: can sleep + * + * Add adapter with dynamic bus number, same with i2c_add_adapter() + * but the adapter will be auto deleted on driver detach. + */ +int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter) +{ +	int ret; + +	ret = i2c_add_adapter(adapter); +	if (ret) +		return ret; + +	return devm_add_action_or_reset(dev, devm_i2c_del_adapter, adapter); +} +EXPORT_SYMBOL_GPL(devm_i2c_add_adapter); +  static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p,  			    u32 def_val, bool use_def)  { | 
