diff mbox series

[v2,1/2] iio: mma8452: Fix probe failing when an i2c_device_id is used

Message ID 20220207103419.309032-1-hdegoede@redhat.com (mailing list archive)
State Superseded
Headers show
Series [v2,1/2] iio: mma8452: Fix probe failing when an i2c_device_id is used | expand

Commit Message

Hans de Goede Feb. 7, 2022, 10:34 a.m. UTC
The mma8452_driver declares both of_match_table and i2c_driver.id_table
match-tables, but its probe() function only checked for of matches.

Add support for i2c_device_id matches. This fixes the driver not loading
on some x86 tablets (e.g. the Nextbook Ares 8) where the i2c_client is
instantiated by platform code using an i2c_device_id.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
- Fix the following smatch warning:
  drivers/iio/accel/mma8452.c:1595 mma8452_probe() error: we previously assumed 'id' could be null (see line 1536)
  Reported-by: kernel test robot <lkp@intel.com>
  Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 drivers/iio/accel/mma8452.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

Comments

Jonathan Cameron Feb. 7, 2022, 9:22 p.m. UTC | #1
On Mon,  7 Feb 2022 11:34:18 +0100
Hans de Goede <hdegoede@redhat.com> wrote:

> The mma8452_driver declares both of_match_table and i2c_driver.id_table
> match-tables, but its probe() function only checked for of matches.
> 
> Add support for i2c_device_id matches. This fixes the driver not loading
> on some x86 tablets (e.g. the Nextbook Ares 8) where the i2c_client is
> instantiated by platform code using an i2c_device_id.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
We've lost the fixes tag from the v1 discussion. 
> ---
> Changes in v2:
> - Fix the following smatch warning:
>   drivers/iio/accel/mma8452.c:1595 mma8452_probe() error: we previously assumed 'id' could be null (see line 1536)
>   Reported-by: kernel test robot <lkp@intel.com>
>   Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  drivers/iio/accel/mma8452.c | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
> index 64b82b4503ad..eaa236cfbabb 100644
> --- a/drivers/iio/accel/mma8452.c
> +++ b/drivers/iio/accel/mma8452.c
> @@ -1523,12 +1523,7 @@ static int mma8452_probe(struct i2c_client *client,
>  	struct iio_dev *indio_dev;
>  	int ret;
>  	const struct of_device_id *match;
> -
> -	match = of_match_device(mma8452_dt_ids, &client->dev);
> -	if (!match) {
> -		dev_err(&client->dev, "unknown device model\n");
> -		return -ENODEV;
> -	}
> +	const char *compatible;
>  
>  	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>  	if (!indio_dev)
> @@ -1537,7 +1532,19 @@ static int mma8452_probe(struct i2c_client *client,
>  	data = iio_priv(indio_dev);
>  	data->client = client;
>  	mutex_init(&data->lock);
> -	data->chip_info = match->data;
> +
> +	if (id) {
> +		compatible = id->name;
> +		data->chip_info = &mma_chip_info_table[id->driver_data];
> +	} else {
> +		match = of_match_device(mma8452_dt_ids, &client->dev);
> +		if (!match) {
> +			dev_err(&client->dev, "unknown device model\n");
> +			return -ENODEV;
> +		}
> +		compatible = match->compatible;

Won't this be "fsl,mma8452" or similar when we want "mma8452"?
That doesn't matter for the dev_info() but it does matter for
indio_dev->name which is part of the userspace ABI.

Probably easiest way to work around this is to just put the names
as an extra entry in the mma_chip_info_table[] so they can
be trivially retrieved in either path.
Sure it's duplication of a string but they are pretty small and
it makes for less special casing in the code.

However, looking again at this code I noticed that you haven't
actually introduced the fact that id->name wouldn't be set which
made me remind myself of how the i2c-core-of.c code works.
It has a quirk.  It will actually always provide the id via
the following path:

of_i2c_register_device()
-> of_i2c_get_board_info()
  -> info->type set in of_modalias_node to the part of the compatible after the comma.

Then
of_i2c_register_device()
-> of_i2c_new_client_device()
  which copies info->type into client->name

Then via i2c_device_probe() for the i2c bus the probe is
called with an i2c_match_id(driver->id_table, client)
to provide the id parameter.

So for devicetree you won't hit your else above as if (id)
will also pass (which is why the id->name before was working).

This path is dropped if we ever move to the probe_new() callback
but for now I think it will just work.

Now, what to do about this.. In similar cases we do
if (client->dev.of_node) {
 of option.
} else {
 id option
}
though this is mostly because people don't feel confident
the i2c id path will always work for device tree just because
(assuming I followed it through correctly) it works today.

Now for ACPI there isn't such a path so when we move to
generic device properties we can't assume id is anything other
than NULL. Note that this driver hasn't previously been converted
to generic fw properties because of the absence of a suitable
fwnode_irq_get_by_name() but Andy pointed out this week that
we now have one available:
https://lore.kernel.org/all/YflfEpKj0ilHnQQm@smile.fi.intel.com/
https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git/commit/?h=i2c/alert-for-acpi&id=ca0acb511c21738b32386ce0f85c284b351d919e

Given that conversion is likely to happen shortly I'd like to
use the pattern above rather than temporarily relying on
the struct i2c_device_id always being available.


It also relies on a one to one match up between compatible
ids and of compatibles which isn't always the case.


Jonathan






> +		data->chip_info = match->data;
> +	}
>  
>  	data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
>  	if (IS_ERR(data->vdd_reg))
> @@ -1581,11 +1588,11 @@ static int mma8452_probe(struct i2c_client *client,
>  	}
>  
>  	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
> -		 match->compatible, data->chip_info->chip_id);
> +		 compatible, data->chip_info->chip_id);
>  
>  	i2c_set_clientdata(client, indio_dev);
>  	indio_dev->info = &mma8452_info;
> -	indio_dev->name = id->name;
> +	indio_dev->name = compatible;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  	indio_dev->channels = data->chip_info->channels;
>  	indio_dev->num_channels = data->chip_info->num_channels;
Hans de Goede Feb. 7, 2022, 10:55 p.m. UTC | #2
Hi,

On 2/7/22 22:22, Jonathan Cameron wrote:
> On Mon,  7 Feb 2022 11:34:18 +0100
> Hans de Goede <hdegoede@redhat.com> wrote:
> 
>> The mma8452_driver declares both of_match_table and i2c_driver.id_table
>> match-tables, but its probe() function only checked for of matches.
>>
>> Add support for i2c_device_id matches. This fixes the driver not loading
>> on some x86 tablets (e.g. the Nextbook Ares 8) where the i2c_client is
>> instantiated by platform code using an i2c_device_id.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> We've lost the fixes tag from the v1 discussion. 

Ah right, so that would be:

Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data")

I'll add that for v3.

>> ---
>> Changes in v2:
>> - Fix the following smatch warning:
>>   drivers/iio/accel/mma8452.c:1595 mma8452_probe() error: we previously assumed 'id' could be null (see line 1536)
>>   Reported-by: kernel test robot <lkp@intel.com>
>>   Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
>> ---
>>  drivers/iio/accel/mma8452.c | 25 ++++++++++++++++---------
>>  1 file changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
>> index 64b82b4503ad..eaa236cfbabb 100644
>> --- a/drivers/iio/accel/mma8452.c
>> +++ b/drivers/iio/accel/mma8452.c
>> @@ -1523,12 +1523,7 @@ static int mma8452_probe(struct i2c_client *client,
>>  	struct iio_dev *indio_dev;
>>  	int ret;
>>  	const struct of_device_id *match;
>> -
>> -	match = of_match_device(mma8452_dt_ids, &client->dev);
>> -	if (!match) {
>> -		dev_err(&client->dev, "unknown device model\n");
>> -		return -ENODEV;
>> -	}
>> +	const char *compatible;
>>  
>>  	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>>  	if (!indio_dev)
>> @@ -1537,7 +1532,19 @@ static int mma8452_probe(struct i2c_client *client,
>>  	data = iio_priv(indio_dev);
>>  	data->client = client;
>>  	mutex_init(&data->lock);
>> -	data->chip_info = match->data;
>> +
>> +	if (id) {
>> +		compatible = id->name;
>> +		data->chip_info = &mma_chip_info_table[id->driver_data];
>> +	} else {
>> +		match = of_match_device(mma8452_dt_ids, &client->dev);
>> +		if (!match) {
>> +			dev_err(&client->dev, "unknown device model\n");
>> +			return -ENODEV;
>> +		}
>> +		compatible = match->compatible;
> 
> Won't this be "fsl,mma8452" or similar when we want "mma8452"?
> That doesn't matter for the dev_info() but it does matter for
> indio_dev->name which is part of the userspace ABI.

If we hit the "else" path then yes, this will be e.g. "fsl,mma8452"
but note how indio_dev->name was previously unconditionally set
to id->name. This did not cause a NULL ptr deref because the i2c-core
sets client->name by using of_modalias_node() which strips the
"fsl," vendor-prefix.

client->name being just "mma8452" means that the id pointer will
be non NULL even for of-instantiated i2c-clients, instead it
will point to the "mma8452" i2c_device_id so we will hit the
if (id) {} path even for of-instantiated i2c-client.

The only case where we can hit the else is if there is an
entry added to the mma8452_dt_ids[] array which is not present
in the mma8452_id[] array, which atm is not the case
(which is confirmed by the lack of bug reports about NULL ptr
derefs).

Note that since client->name matches on of the mma8452_id[]
entries the entire mma8452_dt_ids[] array + the else path
could be completely dropped and things will still work
through a fallback on only using the mma8452_id[] array.

But AFAIK the preferred method for of enumerated clients
is to use of-matches.

So ideally I guess we would do something like this:

match = of_match_device(mma8452_dt_ids, &client->dev);
if (match) {
        compatible = match->compatible;
        data->chip_info = match->data;
} else if (id) {
        compatible = id->name;
        data->chip_info = &mma_chip_info_table[id->driver_data];
} else {
	dev_err(&client->dev, "unknown device model\n");
	return -ENODEV;
}

And then for indio_dev->name do:

indio_dev->name = client->name;

Since that has the vendor-prefix stripped, just like the old
id->name to which it used to be set.

> Probably easiest way to work around this is to just put the names
> as an extra entry in the mma_chip_info_table[] so they can
> be trivially retrieved in either path.
> Sure it's duplication of a string but they are pretty small and
> it makes for less special casing in the code.
> 
> However, looking again at this code I noticed that you haven't
> actually introduced the fact that id->name wouldn't be set which
> made me remind myself of how the i2c-core-of.c code works.
> It has a quirk.  It will actually always provide the id via
> the following path:
> 
> of_i2c_register_device()
> -> of_i2c_get_board_info()
>   -> info->type set in of_modalias_node to the part of the compatible after the comma.
> 
> Then
> of_i2c_register_device()
> -> of_i2c_new_client_device()
>   which copies info->type into client->name
> 
> Then via i2c_device_probe() for the i2c bus the probe is
> called with an i2c_match_id(driver->id_table, client)
> to provide the id parameter.
> 
> So for devicetree you won't hit your else above as if (id)
> will also pass (which is why the id->name before was working).
> 
> This path is dropped if we ever move to the probe_new() callback
> but for now I think it will just work.
> 
> Now, what to do about this.. In similar cases we do
> if (client->dev.of_node) {
>  of option.
> } else {
>  id option
> }
> though this is mostly because people don't feel confident
> the i2c id path will always work for device tree just because
> (assuming I followed it through correctly) it works today.

I should have read on before replying to your initial remark
right away, oops. Right as we both say id will be set even for
of-matches, but only when the of_match and the old i2c_client_id
match tables both have an entry for the model.

> Now for ACPI there isn't such a path so when we move to
> generic device properties we can't assume id is anything other
> than NULL. Note that this driver hasn't previously been converted
> to generic fw properties because of the absence of a suitable
> fwnode_irq_get_by_name() but Andy pointed out this week that
> we now have one available:
> https://lore.kernel.org/all/YflfEpKj0ilHnQQm@smile.fi.intel.com/
> https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git/commit/?h=i2c/alert-for-acpi&id=ca0acb511c21738b32386ce0f85c284b351d919e
> 
> Given that conversion is likely to happen shortly I'd like to
> use the pattern above rather than temporarily relying on
> the struct i2c_device_id always being available.

Hmm, I see, yes my proposed:

	indio_dev->name = client->name;

trick will not work once ACPI also comes into play and I see
that e.g. the bmc150-accel driver already gets the indio_dev->name
from the chip_info_table[] in the ACPI case, so I will prepare
a v3 doing so.

I guess that makes this more 5.18 material then 5.17 though,
but that is fine the platform code instantiating an old
fashioned i2c-client relying on i2c_client_id matching
won't land till 5.18 either.

Regards,

Hans



>> +		data->chip_info = match->data;
>> +	}
>>  
>>  	data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
>>  	if (IS_ERR(data->vdd_reg))
>> @@ -1581,11 +1588,11 @@ static int mma8452_probe(struct i2c_client *client,
>>  	}
>>  
>>  	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
>> -		 match->compatible, data->chip_info->chip_id);
>> +		 compatible, data->chip_info->chip_id);
>>  
>>  	i2c_set_clientdata(client, indio_dev);
>>  	indio_dev->info = &mma8452_info;
>> -	indio_dev->name = id->name;
>> +	indio_dev->name = compatible;
>>  	indio_dev->modes = INDIO_DIRECT_MODE;
>>  	indio_dev->channels = data->chip_info->channels;
>>  	indio_dev->num_channels = data->chip_info->num_channels;
>
Jonathan Cameron Feb. 13, 2022, 6:09 p.m. UTC | #3
On Mon, 7 Feb 2022 23:55:09 +0100
Hans de Goede <hdegoede@redhat.com> wrote:

> Hi,
> 
> On 2/7/22 22:22, Jonathan Cameron wrote:
> > On Mon,  7 Feb 2022 11:34:18 +0100
> > Hans de Goede <hdegoede@redhat.com> wrote:
> >   
> >> The mma8452_driver declares both of_match_table and i2c_driver.id_table
> >> match-tables, but its probe() function only checked for of matches.
> >>
> >> Add support for i2c_device_id matches. This fixes the driver not loading
> >> on some x86 tablets (e.g. the Nextbook Ares 8) where the i2c_client is
> >> instantiated by platform code using an i2c_device_id.
> >>
> >> Signed-off-by: Hans de Goede <hdegoede@redhat.com>  
> > We've lost the fixes tag from the v1 discussion.   
> 
> Ah right, so that would be:
> 
> Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data")
> 
> I'll add that for v3.
> 
> >> ---
> >> Changes in v2:
> >> - Fix the following smatch warning:
> >>   drivers/iio/accel/mma8452.c:1595 mma8452_probe() error: we previously assumed 'id' could be null (see line 1536)
> >>   Reported-by: kernel test robot <lkp@intel.com>
> >>   Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> >> ---
> >>  drivers/iio/accel/mma8452.c | 25 ++++++++++++++++---------
> >>  1 file changed, 16 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
> >> index 64b82b4503ad..eaa236cfbabb 100644
> >> --- a/drivers/iio/accel/mma8452.c
> >> +++ b/drivers/iio/accel/mma8452.c
> >> @@ -1523,12 +1523,7 @@ static int mma8452_probe(struct i2c_client *client,
> >>  	struct iio_dev *indio_dev;
> >>  	int ret;
> >>  	const struct of_device_id *match;
> >> -
> >> -	match = of_match_device(mma8452_dt_ids, &client->dev);
> >> -	if (!match) {
> >> -		dev_err(&client->dev, "unknown device model\n");
> >> -		return -ENODEV;
> >> -	}
> >> +	const char *compatible;
> >>  
> >>  	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> >>  	if (!indio_dev)
> >> @@ -1537,7 +1532,19 @@ static int mma8452_probe(struct i2c_client *client,
> >>  	data = iio_priv(indio_dev);
> >>  	data->client = client;
> >>  	mutex_init(&data->lock);
> >> -	data->chip_info = match->data;
> >> +
> >> +	if (id) {
> >> +		compatible = id->name;
> >> +		data->chip_info = &mma_chip_info_table[id->driver_data];
> >> +	} else {
> >> +		match = of_match_device(mma8452_dt_ids, &client->dev);
> >> +		if (!match) {
> >> +			dev_err(&client->dev, "unknown device model\n");
> >> +			return -ENODEV;
> >> +		}
> >> +		compatible = match->compatible;  
> > 
> > Won't this be "fsl,mma8452" or similar when we want "mma8452"?
> > That doesn't matter for the dev_info() but it does matter for
> > indio_dev->name which is part of the userspace ABI.  
> 
> If we hit the "else" path then yes, this will be e.g. "fsl,mma8452"
> but note how indio_dev->name was previously unconditionally set
> to id->name. This did not cause a NULL ptr deref because the i2c-core
> sets client->name by using of_modalias_node() which strips the
> "fsl," vendor-prefix.
> 
> client->name being just "mma8452" means that the id pointer will
> be non NULL even for of-instantiated i2c-clients, instead it
> will point to the "mma8452" i2c_device_id so we will hit the
> if (id) {} path even for of-instantiated i2c-client.
> 
> The only case where we can hit the else is if there is an
> entry added to the mma8452_dt_ids[] array which is not present
> in the mma8452_id[] array, which atm is not the case
> (which is confirmed by the lack of bug reports about NULL ptr
> derefs).
> 
> Note that since client->name matches on of the mma8452_id[]
> entries the entire mma8452_dt_ids[] array + the else path
> could be completely dropped and things will still work
> through a fallback on only using the mma8452_id[] array.
> 
> But AFAIK the preferred method for of enumerated clients
> is to use of-matches.
> 
> So ideally I guess we would do something like this:
> 
> match = of_match_device(mma8452_dt_ids, &client->dev);
> if (match) {
>         compatible = match->compatible;
>         data->chip_info = match->data;
> } else if (id) {
>         compatible = id->name;
>         data->chip_info = &mma_chip_info_table[id->driver_data];
> } else {
> 	dev_err(&client->dev, "unknown device model\n");
> 	return -ENODEV;
> }
> 
> And then for indio_dev->name do:
> 
> indio_dev->name = client->name;
> 
> Since that has the vendor-prefix stripped, just like the old
> id->name to which it used to be set.
> 
> > Probably easiest way to work around this is to just put the names
> > as an extra entry in the mma_chip_info_table[] so they can
> > be trivially retrieved in either path.
> > Sure it's duplication of a string but they are pretty small and
> > it makes for less special casing in the code.
> > 
> > However, looking again at this code I noticed that you haven't
> > actually introduced the fact that id->name wouldn't be set which
> > made me remind myself of how the i2c-core-of.c code works.
> > It has a quirk.  It will actually always provide the id via
> > the following path:
> > 
> > of_i2c_register_device()  
> > -> of_i2c_get_board_info()
> >   -> info->type set in of_modalias_node to the part of the compatible after the comma.  
> > 
> > Then
> > of_i2c_register_device()  
> > -> of_i2c_new_client_device()  
> >   which copies info->type into client->name
> > 
> > Then via i2c_device_probe() for the i2c bus the probe is
> > called with an i2c_match_id(driver->id_table, client)
> > to provide the id parameter.
> > 
> > So for devicetree you won't hit your else above as if (id)
> > will also pass (which is why the id->name before was working).
> > 
> > This path is dropped if we ever move to the probe_new() callback
> > but for now I think it will just work.
> > 
> > Now, what to do about this.. In similar cases we do
> > if (client->dev.of_node) {
> >  of option.
> > } else {
> >  id option
> > }
> > though this is mostly because people don't feel confident
> > the i2c id path will always work for device tree just because
> > (assuming I followed it through correctly) it works today.  
> 
> I should have read on before replying to your initial remark
> right away, oops. Right as we both say id will be set even for
> of-matches, but only when the of_match and the old i2c_client_id
> match tables both have an entry for the model.
> 
> > Now for ACPI there isn't such a path so when we move to
> > generic device properties we can't assume id is anything other
> > than NULL. Note that this driver hasn't previously been converted
> > to generic fw properties because of the absence of a suitable
> > fwnode_irq_get_by_name() but Andy pointed out this week that
> > we now have one available:
> > https://lore.kernel.org/all/YflfEpKj0ilHnQQm@smile.fi.intel.com/
> > https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git/commit/?h=i2c/alert-for-acpi&id=ca0acb511c21738b32386ce0f85c284b351d919e
> > 
> > Given that conversion is likely to happen shortly I'd like to
> > use the pattern above rather than temporarily relying on
> > the struct i2c_device_id always being available.  
> 
> Hmm, I see, yes my proposed:
> 
> 	indio_dev->name = client->name;
> 
> trick will not work once ACPI also comes into play and I see
> that e.g. the bmc150-accel driver already gets the indio_dev->name
> from the chip_info_table[] in the ACPI case, so I will prepare
> a v3 doing so.
> 
> I guess that makes this more 5.18 material then 5.17 though,
> but that is fine the platform code instantiating an old
> fashioned i2c-client relying on i2c_client_id matching
> won't land till 5.18 either.
Ah. IN that case I'll yank v3 from the fixes branch over to
the one for next cycle and can apply patch 2 as well.

Thanks,

J
> 
> Regards,
> 
> Hans
> 
> 
> 
> >> +		data->chip_info = match->data;
> >> +	}
> >>  
> >>  	data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
> >>  	if (IS_ERR(data->vdd_reg))
> >> @@ -1581,11 +1588,11 @@ static int mma8452_probe(struct i2c_client *client,
> >>  	}
> >>  
> >>  	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
> >> -		 match->compatible, data->chip_info->chip_id);
> >> +		 compatible, data->chip_info->chip_id);
> >>  
> >>  	i2c_set_clientdata(client, indio_dev);
> >>  	indio_dev->info = &mma8452_info;
> >> -	indio_dev->name = id->name;
> >> +	indio_dev->name = compatible;
> >>  	indio_dev->modes = INDIO_DIRECT_MODE;
> >>  	indio_dev->channels = data->chip_info->channels;
> >>  	indio_dev->num_channels = data->chip_info->num_channels;  
> >   
>
diff mbox series

Patch

diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 64b82b4503ad..eaa236cfbabb 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1523,12 +1523,7 @@  static int mma8452_probe(struct i2c_client *client,
 	struct iio_dev *indio_dev;
 	int ret;
 	const struct of_device_id *match;
-
-	match = of_match_device(mma8452_dt_ids, &client->dev);
-	if (!match) {
-		dev_err(&client->dev, "unknown device model\n");
-		return -ENODEV;
-	}
+	const char *compatible;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
@@ -1537,7 +1532,19 @@  static int mma8452_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	data->client = client;
 	mutex_init(&data->lock);
-	data->chip_info = match->data;
+
+	if (id) {
+		compatible = id->name;
+		data->chip_info = &mma_chip_info_table[id->driver_data];
+	} else {
+		match = of_match_device(mma8452_dt_ids, &client->dev);
+		if (!match) {
+			dev_err(&client->dev, "unknown device model\n");
+			return -ENODEV;
+		}
+		compatible = match->compatible;
+		data->chip_info = match->data;
+	}
 
 	data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
 	if (IS_ERR(data->vdd_reg))
@@ -1581,11 +1588,11 @@  static int mma8452_probe(struct i2c_client *client,
 	}
 
 	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
-		 match->compatible, data->chip_info->chip_id);
+		 compatible, data->chip_info->chip_id);
 
 	i2c_set_clientdata(client, indio_dev);
 	indio_dev->info = &mma8452_info;
-	indio_dev->name = id->name;
+	indio_dev->name = compatible;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = data->chip_info->channels;
 	indio_dev->num_channels = data->chip_info->num_channels;