Message ID | 20110401112030.GA3447@sortiz-mobl |
---|---|
State | Not Applicable, archived |
Delegated to: | David Miller |
Headers | show |
On Fri, 1 Apr 2011 13:20:31 +0200 Samuel Ortiz <sameo@linux.intel.com> wrote: > Hi Grant, > > On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: [...] > > Gah. Not all devices instantiated via mfd will be an mfd device, > > which means that the driver may very well expect an *entirely > > different* platform_device pointer; which further means a very high > > potential of incorrectly dereferenced structures (as evidenced by a > > patch series that is not bisectable). For instance, the xilinx ip > > cores are used by more than just mfd. > I agree. Since the vast majority of the MFD subdevices are MFD > specific IPs, I overlooked that part. The impacted drivers are the > timberdale and the DaVinci voice codec ones. Can you please provide pointers to what you're referring to? The only code that I could find that created platform devices prefixed with 'timb-' or named 'xilinx_spi' was drivers/mfd/timberdale.c. > To fix that problem I propose 2 alternatives: > > 1) When declaring the sub devices cells, the MFD driver should > specify an mfd_data_size value for sub devices that are not MFD > specific. It's the MFD driver responsibility to set the cell > properly, and the non MFD specific drivers are kept MFD agnostic. > See my patch below for the timberdale case. > > 2) Revert the mfd_get_data() call for getting sub devices platform > data pointers. That was introduced to ease the MFD cell sharing work, > so if we take this route we'll need the cs5535 MFD driver to pass its > cells as platform_data pointer. Andres, can you confirm that this > would be fine for the mfd_clone_cell() routine to keep working ? It would break mfd_clone_cell, as it uses mfd_get_cell to grab the one to clone. We could change it to accept the cell as an argument. It would also break mfd_cell_enable/disable, of course. > > Patch for solution 1: > > > drivers/mfd/mfd-core.c | 13 ++++++++++--- > drivers/mfd/timberdale.c | 11 +++++++++++ > include/linux/mfd/core.h | 1 + > drivers/i2c/busses/i2c-ocores.c | 3 +-- > drivers/i2c/busses/i2c-xiic.c | 3 +-- > drivers/net/ks8842.c | 3 +-- > drivers/spi/xilinx_spi.c | 3 +-- > 7 files changed, 26 insertions(+), 11 deletions(-) > > diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c > index d01574d..8abe510 100644 > --- a/drivers/mfd/mfd-core.c > +++ b/drivers/mfd/mfd-core.c > @@ -75,9 +75,16 @@ static int mfd_add_device(struct device *parent, > int id, > pdev->dev.parent = parent; > > - ret = platform_device_add_data(pdev, cell, sizeof(*cell)); > - if (ret) > - goto fail_res; > + if (cell->mfd_data_size > 0) { > + ret = platform_device_add_data(pdev, > + cell->mfd_data, > cell->mfd_data_size); > + if (ret) > + goto fail_res; > + } else { > + ret = platform_device_add_data(pdev, cell, > sizeof(*cell)); > + if (ret) > + goto fail_res; > + } > > for (r = 0; r < cell->num_resources; r++) { > res[r].name = cell->resources[r].name; -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Apr 1, 2011 at 11:47 AM, Andres Salomon <dilinger@queued.net> wrote: > On Fri, 1 Apr 2011 13:20:31 +0200 > Samuel Ortiz <sameo@linux.intel.com> wrote: > >> Hi Grant, >> >> On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: > [...] >> > Gah. Not all devices instantiated via mfd will be an mfd device, >> > which means that the driver may very well expect an *entirely >> > different* platform_device pointer; which further means a very high >> > potential of incorrectly dereferenced structures (as evidenced by a >> > patch series that is not bisectable). For instance, the xilinx ip >> > cores are used by more than just mfd. >> I agree. Since the vast majority of the MFD subdevices are MFD >> specific IPs, I overlooked that part. The impacted drivers are the >> timberdale and the DaVinci voice codec ones. Another option is you could do this for MFD devices: struct mfd_device { struct platform_devce pdev; struct mfd_cell *cell; }; However, that requires that drivers using the mfd_cell will *never* get instantiated outside of the mfd infrastructure, and there is no way to protect against this so it is probably a bad idea. Or, mfd_cell could be added to platform_device directly which would *by far* be the safest option at the cost of every platform_device having a mostly unused mfd_cell pointer. Not a significant cost in my opinion. One last option is I'm prototyping a way to add type-safe structure pointers to a device, but that requires nasty CPP tricks and it's not complete yet. The cure might be worse than the disease here. g. > > Can you please provide pointers to what you're referring to? The only > code that I could find that created platform devices prefixed with > 'timb-' or named 'xilinx_spi' was drivers/mfd/timberdale.c. > > > >> To fix that problem I propose 2 alternatives: >> >> 1) When declaring the sub devices cells, the MFD driver should >> specify an mfd_data_size value for sub devices that are not MFD >> specific. It's the MFD driver responsibility to set the cell >> properly, and the non MFD specific drivers are kept MFD agnostic. >> See my patch below for the timberdale case. This approach worries me because it changes the behaviour on a per-device basis. That could be difficult to maintain a mental model for. I'd rather see consistent behaviour. >> >> 2) Revert the mfd_get_data() call for getting sub devices platform >> data pointers. That was introduced to ease the MFD cell sharing work, >> so if we take this route we'll need the cs5535 MFD driver to pass its >> cells as platform_data pointer. Andres, can you confirm that this >> would be fine for the mfd_clone_cell() routine to keep working ? > > It would break mfd_clone_cell, as it uses mfd_get_cell to grab the one > to clone. We could change it to accept the cell as an argument. It > would also break mfd_cell_enable/disable, of course. > > > >> >> Patch for solution 1: >> >> >> drivers/mfd/mfd-core.c | 13 ++++++++++--- >> drivers/mfd/timberdale.c | 11 +++++++++++ >> include/linux/mfd/core.h | 1 + >> drivers/i2c/busses/i2c-ocores.c | 3 +-- >> drivers/i2c/busses/i2c-xiic.c | 3 +-- >> drivers/net/ks8842.c | 3 +-- >> drivers/spi/xilinx_spi.c | 3 +-- >> 7 files changed, 26 insertions(+), 11 deletions(-) >> >> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c >> index d01574d..8abe510 100644 >> --- a/drivers/mfd/mfd-core.c >> +++ b/drivers/mfd/mfd-core.c >> @@ -75,9 +75,16 @@ static int mfd_add_device(struct device *parent, >> int id, >> pdev->dev.parent = parent; >> >> - ret = platform_device_add_data(pdev, cell, sizeof(*cell)); >> - if (ret) >> - goto fail_res; >> + if (cell->mfd_data_size > 0) { >> + ret = platform_device_add_data(pdev, >> + cell->mfd_data, >> cell->mfd_data_size); >> + if (ret) >> + goto fail_res; >> + } else { >> + ret = platform_device_add_data(pdev, cell, >> sizeof(*cell)); >> + if (ret) >> + goto fail_res; >> + } >> >> for (r = 0; r < cell->num_resources; r++) { >> res[r].name = cell->resources[r].name; >
On Fri, Apr 1, 2011 at 11:56 AM, Grant Likely <grant.likely@secretlab.ca> wrote: > On Fri, Apr 1, 2011 at 11:47 AM, Andres Salomon <dilinger@queued.net> wrote: >> On Fri, 1 Apr 2011 13:20:31 +0200 >> Samuel Ortiz <sameo@linux.intel.com> wrote: >> >>> Hi Grant, >>> >>> On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: >> [...] >>> > Gah. Not all devices instantiated via mfd will be an mfd device, >>> > which means that the driver may very well expect an *entirely >>> > different* platform_device pointer; which further means a very high >>> > potential of incorrectly dereferenced structures (as evidenced by a >>> > patch series that is not bisectable). For instance, the xilinx ip >>> > cores are used by more than just mfd. >>> I agree. Since the vast majority of the MFD subdevices are MFD >>> specific IPs, I overlooked that part. The impacted drivers are the >>> timberdale and the DaVinci voice codec ones. > > Another option is you could do this for MFD devices: > > struct mfd_device { > struct platform_devce pdev; > struct mfd_cell *cell; > }; > > However, that requires that drivers using the mfd_cell will *never* > get instantiated outside of the mfd infrastructure, and there is no > way to protect against this so it is probably a bad idea. > > Or, mfd_cell could be added to platform_device directly which would > *by far* be the safest option at the cost of every platform_device > having a mostly unused mfd_cell pointer. Not a significant cost in my > opinion. > > One last option is I'm prototyping a way to add type-safe structure > pointers to a device, but that requires nasty CPP tricks and it's not > complete yet. The cure might be worse than the disease here. And yet another option is to create a mfd_bus_type, but that probably isn't helpful since the one of the purposes of MFDs is that it is a collection of non-detectable memory mapped devices that platform_bus_type is intended to handle. g. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Apr 01, 2011 at 11:56:35AM -0600, Grant Likely wrote: > On Fri, Apr 1, 2011 at 11:47 AM, Andres Salomon <dilinger@queued.net> wrote: > > On Fri, 1 Apr 2011 13:20:31 +0200 > > Samuel Ortiz <sameo@linux.intel.com> wrote: > > > >> Hi Grant, > >> > >> On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: > > [...] > >> > Gah. Not all devices instantiated via mfd will be an mfd device, > >> > which means that the driver may very well expect an *entirely > >> > different* platform_device pointer; which further means a very high > >> > potential of incorrectly dereferenced structures (as evidenced by a > >> > patch series that is not bisectable). For instance, the xilinx ip > >> > cores are used by more than just mfd. > >> I agree. Since the vast majority of the MFD subdevices are MFD > >> specific IPs, I overlooked that part. The impacted drivers are the > >> timberdale and the DaVinci voice codec ones. > > Another option is you could do this for MFD devices: > > struct mfd_device { > struct platform_devce pdev; > struct mfd_cell *cell; > }; > > However, that requires that drivers using the mfd_cell will *never* > get instantiated outside of the mfd infrastructure, and there is no > way to protect against this so it is probably a bad idea. > > Or, mfd_cell could be added to platform_device directly which would > *by far* be the safest option at the cost of every platform_device > having a mostly unused mfd_cell pointer. Not a significant cost in my > opinion. I thought about this one, but I had the impression people would want to kill me for adding an MFD specific pointer to platform_device. I guess it's worth giving it a try since it would be a simple and safe solution. I'll look at it later this weekend. Thanks for the input. Cheers, Samuel.
On Fri, Apr 1, 2011 at 5:52 PM, Samuel Ortiz <sameo@linux.intel.com> wrote: > On Fri, Apr 01, 2011 at 11:56:35AM -0600, Grant Likely wrote: >> On Fri, Apr 1, 2011 at 11:47 AM, Andres Salomon <dilinger@queued.net> wrote: >> > On Fri, 1 Apr 2011 13:20:31 +0200 >> > Samuel Ortiz <sameo@linux.intel.com> wrote: >> > >> >> Hi Grant, >> >> >> >> On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: >> > [...] >> >> > Gah. Not all devices instantiated via mfd will be an mfd device, >> >> > which means that the driver may very well expect an *entirely >> >> > different* platform_device pointer; which further means a very high >> >> > potential of incorrectly dereferenced structures (as evidenced by a >> >> > patch series that is not bisectable). For instance, the xilinx ip >> >> > cores are used by more than just mfd. >> >> I agree. Since the vast majority of the MFD subdevices are MFD >> >> specific IPs, I overlooked that part. The impacted drivers are the >> >> timberdale and the DaVinci voice codec ones. >> >> Another option is you could do this for MFD devices: >> >> struct mfd_device { >> struct platform_devce pdev; >> struct mfd_cell *cell; >> }; >> >> However, that requires that drivers using the mfd_cell will *never* >> get instantiated outside of the mfd infrastructure, and there is no >> way to protect against this so it is probably a bad idea. >> >> Or, mfd_cell could be added to platform_device directly which would >> *by far* be the safest option at the cost of every platform_device >> having a mostly unused mfd_cell pointer. Not a significant cost in my >> opinion. > I thought about this one, but I had the impression people would want to kill > me for adding an MFD specific pointer to platform_device. I guess it's worth > giving it a try since it would be a simple and safe solution. > I'll look at it later this weekend. > > Thanks for the input. [cc'ing gregkh because we're talking about modifying struct platform_device] I'll back you up on this one. It is a far better solution than the alternatives. At least with mfd, it covers a large set of devices. I think there is a strong argument for doing this. Or alternatively, the particular interesting fields from mfd_cell could be added to platform_device. What information do child devices need access to? g. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, 1 Apr 2011 17:58:44 -0600 Grant Likely <grant.likely@secretlab.ca> wrote: > On Fri, Apr 1, 2011 at 5:52 PM, Samuel Ortiz <sameo@linux.intel.com> > wrote: > > On Fri, Apr 01, 2011 at 11:56:35AM -0600, Grant Likely wrote: > >> On Fri, Apr 1, 2011 at 11:47 AM, Andres Salomon > >> <dilinger@queued.net> wrote: > >> > On Fri, 1 Apr 2011 13:20:31 +0200 > >> > Samuel Ortiz <sameo@linux.intel.com> wrote: > >> > > >> >> Hi Grant, > >> >> > >> >> On Thu, Mar 31, 2011 at 05:05:22PM -0600, Grant Likely wrote: > >> > [...] > >> >> > Gah. Not all devices instantiated via mfd will be an mfd > >> >> > device, which means that the driver may very well expect an > >> >> > *entirely different* platform_device pointer; which further > >> >> > means a very high potential of incorrectly dereferenced > >> >> > structures (as evidenced by a patch series that is not > >> >> > bisectable). For instance, the xilinx ip cores are used by > >> >> > more than just mfd. > >> >> I agree. Since the vast majority of the MFD subdevices are MFD > >> >> specific IPs, I overlooked that part. The impacted drivers are > >> >> the timberdale and the DaVinci voice codec ones. > >> > >> Another option is you could do this for MFD devices: > >> > >> struct mfd_device { > >> struct platform_devce pdev; > >> struct mfd_cell *cell; > >> }; > >> > >> However, that requires that drivers using the mfd_cell will *never* > >> get instantiated outside of the mfd infrastructure, and there is no > >> way to protect against this so it is probably a bad idea. > >> > >> Or, mfd_cell could be added to platform_device directly which would > >> *by far* be the safest option at the cost of every platform_device > >> having a mostly unused mfd_cell pointer. Not a significant cost > >> in my opinion. > > I thought about this one, but I had the impression people would > > want to kill me for adding an MFD specific pointer to > > platform_device. I guess it's worth giving it a try since it would > > be a simple and safe solution. I'll look at it later this weekend. > > > > Thanks for the input. > > [cc'ing gregkh because we're talking about modifying struct > platform_device] > > I'll back you up on this one. It is a far better solution than the > alternatives. At least with mfd, it covers a large set of devices. I > think there is a strong argument for doing this. Or alternatively, > the particular interesting fields from mfd_cell could be added to > platform_device. What information do child devices need access to? > This was one of the things I was originally tempted to do (adding mfd fields to platform_device). I didn't think it would fly. I can look at this stuff or help out once I have a stable internet connection and I'm all moved in to my new place (which should be Wednesday). -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d01574d..8abe510 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -75,9 +75,16 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; - ret = platform_device_add_data(pdev, cell, sizeof(*cell)); - if (ret) - goto fail_res; + if (cell->mfd_data_size > 0) { + ret = platform_device_add_data(pdev, + cell->mfd_data, cell->mfd_data_size); + if (ret) + goto fail_res; + } else { + ret = platform_device_add_data(pdev, cell, sizeof(*cell)); + if (ret) + goto fail_res; + } for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 94c6c8a..b4d2d09 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -396,6 +396,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .mfd_data = &timberdale_xiic_platform_data, + .mfd_data_size = sizeof(timberdale_xiic_platform_data) }, { .name = "timb-gpio", @@ -420,12 +421,14 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .mfd_data = &timberdale_xspi_platform_data, + .mfd_data_size = sizeof(timberdale_xspi_platform_data) }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .mfd_data = &timberdale_ks8842_platform_data, + .mfd_data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -451,6 +454,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .mfd_data = &timberdale_xiic_platform_data, + .mfd_data_size = sizeof(timberdale_xiic_platform_data) }, { .name = "timb-gpio", @@ -480,12 +484,14 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .mfd_data = &timberdale_xspi_platform_data, + .mfd_data_size = sizeof(timberdale_xspi_platform_data) }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .mfd_data = &timberdale_ks8842_platform_data, + .mfd_data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -506,6 +512,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .mfd_data = &timberdale_xiic_platform_data, + .mfd_data_size = sizeof(timberdale_xiic_platform_data) }, { .name = "timb-gpio", @@ -530,6 +537,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .mfd_data = &timberdale_xspi_platform_data, + .mfd_data_size = sizeof(timberdale_xspi_platform_data) }, }; @@ -550,6 +558,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .num_resources = ARRAY_SIZE(timberdale_ocores_resources), .resources = timberdale_ocores_resources, .mfd_data = &timberdale_ocores_platform_data, + .mfd_data_size = sizeof(timberdale_ocores_platform_data) }, { .name = "timb-gpio", @@ -574,12 +583,14 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .mfd_data = &timberdale_xspi_platform_data, + .mfd_data_size = sizeof(timberdale_xspi_platform_data) }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .mfd_data = &timberdale_ks8842_platform_data, + .mfd_data_size = sizeof(timberdale_ks8842_platform_data) }, }; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index ad1b19a..3687e10 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -35,6 +35,7 @@ struct mfd_cell { /* mfd_data can be used to pass data to client drivers */ void *mfd_data; + size_t mfd_data_size; /* * These resources can be specified relative to the parent device. diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index fee1a26..1b46a9d 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -49,7 +49,6 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> @@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return -EIO; } - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (pdata) { i2c->regstep = pdata->regstep; i2c->clock_khz = pdata->clock_khz; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 9fbd7e6..a9c419e 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -34,7 +34,6 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> @@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev) if (irq < 0) goto resource_missing; - pdata = mfd_get_data(pdev); + pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data; if (!pdata) return -EINVAL; diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index efd44af..928b2b8 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) struct resource *iomem; struct net_device *netdev; struct ks8842_adapter *adapter; - struct ks8842_platform_data *pdata = mfd_get_data(pdev); + struct ks8842_platform_data *pdata = pdev->dev.platform_data; u16 id; unsigned i; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index c69c6f2..4d2c75d 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/of.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/spi/xilinx_spi.h> @@ -471,7 +470,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev) struct spi_master *master; u8 i; - pdata = mfd_get_data(dev); + pdata = dev->dev.platform_data; if (pdata) { num_cs = pdata->num_chipselect; little_endian = pdata->little_endian;