[1/2] mmc: mmci: Initial support to manage variant specific callbacks

Message ID 20180713111523.25962-1-ulf.hansson@linaro.org
State New
Headers show
Series
  • [1/2] mmc: mmci: Initial support to manage variant specific callbacks
Related show

Commit Message

Ulf Hansson July 13, 2018, 11:15 a.m.
To be able to better support different mmci variants, we need to be able to
use variant specific callbacks, rather than continue to sprinkle the code
with additional variant data. To move in this direction, let's add an
optional ->init() callback to the variant data struct, which variants shall
use to assign the mmci_host_ops pointer.

Using an ->init() callback enables us to partition the code between
different files. To allow separate mmci variant files to implement the
variant specifics, let's also move the definition of the struct
variant_data to the common mmci header file.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

---
 drivers/mmc/host/mmci.c | 75 ++------------------------------------
 drivers/mmc/host/mmci.h | 80 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 82 insertions(+), 73 deletions(-)

-- 
2.17.1

Comments

Ludovic BARRE July 13, 2018, 1:14 p.m. | #1
On 07/13/2018 01:15 PM, Ulf Hansson wrote:
> To be able to better support different mmci variants, we need to be able to

> use variant specific callbacks, rather than continue to sprinkle the code

> with additional variant data. To move in this direction, let's add an

> optional ->init() callback to the variant data struct, which variants shall

> use to assign the mmci_host_ops pointer.

> 

> Using an ->init() callback enables us to partition the code between

> different files. To allow separate mmci variant files to implement the

> variant specifics, let's also move the definition of the struct

> variant_data to the common mmci header file.

> 

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>


Reviewed-by: Ludovic Barre <ludovic.barre@st.com>


> ---

>   drivers/mmc/host/mmci.c | 75 ++------------------------------------

>   drivers/mmc/host/mmci.h | 80 ++++++++++++++++++++++++++++++++++++++++-

>   2 files changed, 82 insertions(+), 73 deletions(-)

> 

> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c

> index f1849775e47e..e907a0a866da 100644

> --- a/drivers/mmc/host/mmci.c

> +++ b/drivers/mmc/host/mmci.c

> @@ -48,78 +48,6 @@

>   

>   static unsigned int fmax = 515633;

>   

> -/**

> - * struct variant_data - MMCI variant-specific quirks

> - * @clkreg: default value for MCICLOCK register

> - * @clkreg_enable: enable value for MMCICLOCK register

> - * @clkreg_8bit_bus_enable: enable value for 8 bit bus

> - * @clkreg_neg_edge_enable: enable value for inverted data/cmd output

> - * @datalength_bits: number of bits in the MMCIDATALENGTH register

> - * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY

> - *	      is asserted (likewise for RX)

> - * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY

> - *		  is asserted (likewise for RX)

> - * @data_cmd_enable: enable value for data commands.

> - * @st_sdio: enable ST specific SDIO logic

> - * @st_clkdiv: true if using a ST-specific clock divider algorithm

> - * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.

> - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register

> - * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl

> - *		     register

> - * @datactrl_mask_sdio: SDIO enable mask in datactrl register

> - * @pwrreg_powerup: power up value for MMCIPOWER register

> - * @f_max: maximum clk frequency supported by the controller.

> - * @signal_direction: input/out direction of bus signals can be indicated

> - * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock

> - * @busy_detect: true if the variant supports busy detection on DAT0.

> - * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM

> - * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register

> - *		      indicating that the card is busy

> - * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for

> - *		      getting busy end detection interrupts

> - * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply

> - * @explicit_mclk_control: enable explicit mclk control in driver.

> - * @qcom_fifo: enables qcom specific fifo pio read logic.

> - * @qcom_dml: enables qcom specific dma glue for dma transfers.

> - * @reversed_irq_handling: handle data irq before cmd irq.

> - * @mmcimask1: true if variant have a MMCIMASK1 register.

> - * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS

> - *	       register.

> - * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register

> - */

> -struct variant_data {

> -	unsigned int		clkreg;

> -	unsigned int		clkreg_enable;

> -	unsigned int		clkreg_8bit_bus_enable;

> -	unsigned int		clkreg_neg_edge_enable;

> -	unsigned int		datalength_bits;

> -	unsigned int		fifosize;

> -	unsigned int		fifohalfsize;

> -	unsigned int		data_cmd_enable;

> -	unsigned int		datactrl_mask_ddrmode;

> -	unsigned int		datactrl_mask_sdio;

> -	bool			st_sdio;

> -	bool			st_clkdiv;

> -	bool			blksz_datactrl16;

> -	bool			blksz_datactrl4;

> -	u32			pwrreg_powerup;

> -	u32			f_max;

> -	bool			signal_direction;

> -	bool			pwrreg_clkgate;

> -	bool			busy_detect;

> -	u32			busy_dpsm_flag;

> -	u32			busy_detect_flag;

> -	u32			busy_detect_mask;

> -	bool			pwrreg_nopower;

> -	bool			explicit_mclk_control;

> -	bool			qcom_fifo;

> -	bool			qcom_dml;

> -	bool			reversed_irq_handling;

> -	bool			mmcimask1;

> -	u32			start_err;

> -	u32			opendrain;

> -};

> -

>   static struct variant_data variant_arm = {

>   	.fifosize		= 16 * 4,

>   	.fifohalfsize		= 8 * 4,

> @@ -1706,6 +1634,9 @@ static int mmci_probe(struct amba_device *dev,

>   		goto clk_disable;

>   	}

>   

> +	if (variant->init)

> +		variant->init(host);

> +

>   	/*

>   	 * The ARM and ST versions of the block have slightly different

>   	 * clock divider equations which means that the minimum divider

> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h

> index f91cdf7f6dae..f2eff0cc6934 100644

> --- a/drivers/mmc/host/mmci.h

> +++ b/drivers/mmc/host/mmci.h

> @@ -195,8 +195,85 @@

>   #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"

>   

>   struct clk;

> -struct variant_data;

>   struct dma_chan;

> +struct mmci_host;

> +

> +/**

> + * struct variant_data - MMCI variant-specific quirks

> + * @clkreg: default value for MCICLOCK register

> + * @clkreg_enable: enable value for MMCICLOCK register

> + * @clkreg_8bit_bus_enable: enable value for 8 bit bus

> + * @clkreg_neg_edge_enable: enable value for inverted data/cmd output

> + * @datalength_bits: number of bits in the MMCIDATALENGTH register

> + * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY

> + *	      is asserted (likewise for RX)

> + * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY

> + *		  is asserted (likewise for RX)

> + * @data_cmd_enable: enable value for data commands.

> + * @st_sdio: enable ST specific SDIO logic

> + * @st_clkdiv: true if using a ST-specific clock divider algorithm

> + * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.

> + * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register

> + * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl

> + *		     register

> + * @datactrl_mask_sdio: SDIO enable mask in datactrl register

> + * @pwrreg_powerup: power up value for MMCIPOWER register

> + * @f_max: maximum clk frequency supported by the controller.

> + * @signal_direction: input/out direction of bus signals can be indicated

> + * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock

> + * @busy_detect: true if the variant supports busy detection on DAT0.

> + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM

> + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register

> + *		      indicating that the card is busy

> + * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for

> + *		      getting busy end detection interrupts

> + * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply

> + * @explicit_mclk_control: enable explicit mclk control in driver.

> + * @qcom_fifo: enables qcom specific fifo pio read logic.

> + * @qcom_dml: enables qcom specific dma glue for dma transfers.

> + * @reversed_irq_handling: handle data irq before cmd irq.

> + * @mmcimask1: true if variant have a MMCIMASK1 register.

> + * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS

> + *	       register.

> + * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register

> + */

> +struct variant_data {

> +	unsigned int		clkreg;

> +	unsigned int		clkreg_enable;

> +	unsigned int		clkreg_8bit_bus_enable;

> +	unsigned int		clkreg_neg_edge_enable;

> +	unsigned int		datalength_bits;

> +	unsigned int		fifosize;

> +	unsigned int		fifohalfsize;

> +	unsigned int		data_cmd_enable;

> +	unsigned int		datactrl_mask_ddrmode;

> +	unsigned int		datactrl_mask_sdio;

> +	bool			st_sdio;

> +	bool			st_clkdiv;

> +	bool			blksz_datactrl16;

> +	bool			blksz_datactrl4;

> +	u32			pwrreg_powerup;

> +	u32			f_max;

> +	bool			signal_direction;

> +	bool			pwrreg_clkgate;

> +	bool			busy_detect;

> +	u32			busy_dpsm_flag;

> +	u32			busy_detect_flag;

> +	u32			busy_detect_mask;

> +	bool			pwrreg_nopower;

> +	bool			explicit_mclk_control;

> +	bool			qcom_fifo;

> +	bool			qcom_dml;

> +	bool			reversed_irq_handling;

> +	bool			mmcimask1;

> +	u32			start_err;

> +	u32			opendrain;

> +	void (*init)(struct mmci_host *host);

> +};

> +

> +/* mmci variant callbacks */

> +struct mmci_host_ops {

> +};

>   

>   struct mmci_host_next {

>   	struct dma_async_tx_descriptor	*dma_desc;

> @@ -228,6 +305,7 @@ struct mmci_host {

>   	u32			mask1_reg;

>   	bool			vqmmc_enabled;

>   	struct mmci_platform_data *plat;

> +	struct mmci_host_ops	*ops;

>   	struct variant_data	*variant;

>   	struct pinctrl		*pinctrl;

>   	struct pinctrl_state	*pins_default;

> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij July 13, 2018, 3:12 p.m. | #2
On Fri, Jul 13, 2018 at 1:15 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> To be able to better support different mmci variants, we need to be able to

> use variant specific callbacks, rather than continue to sprinkle the code

> with additional variant data. To move in this direction, let's add an

> optional ->init() callback to the variant data struct, which variants shall

> use to assign the mmci_host_ops pointer.

>

> Using an ->init() callback enables us to partition the code between

> different files. To allow separate mmci variant files to implement the

> variant specifics, let's also move the definition of the struct

> variant_data to the common mmci header file.

>

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>


Good idea!

> +       if (variant->init)

> +               variant->init(host);

(...)
> +struct variant_data {

(...)
> +       void (*init)(struct mmci_host *host);

> +};

> +

> +/* mmci variant callbacks */

> +struct mmci_host_ops {

> +};


Why not have the .init() callback inside the struct mmci_host_ops vtable?

If you think it's hairy to dereference twice like mmci->variant->ops(foo)
you can always copy the pointer mmci->ops = variant->ops and
be done with it.

It's easy to just assign it directly in the variant data that way:

variant_foo = {
    (...)
    .ops = {
           .init = ...

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson July 16, 2018, 10:40 a.m. | #3
On 13 July 2018 at 17:12, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Fri, Jul 13, 2018 at 1:15 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

>

>> To be able to better support different mmci variants, we need to be able to

>> use variant specific callbacks, rather than continue to sprinkle the code

>> with additional variant data. To move in this direction, let's add an

>> optional ->init() callback to the variant data struct, which variants shall

>> use to assign the mmci_host_ops pointer.

>>

>> Using an ->init() callback enables us to partition the code between

>> different files. To allow separate mmci variant files to implement the

>> variant specifics, let's also move the definition of the struct

>> variant_data to the common mmci header file.

>>

>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

>

> Good idea!


Thanks!

>

>> +       if (variant->init)

>> +               variant->init(host);

> (...)

>> +struct variant_data {

> (...)

>> +       void (*init)(struct mmci_host *host);

>> +};

>> +

>> +/* mmci variant callbacks */

>> +struct mmci_host_ops {

>> +};

>

> Why not have the .init() callback inside the struct mmci_host_ops vtable?


The idea is to let the ->init() callback to be assigned at compilation
time and couple it with the amba_id. In that way, we can keep having
one common driver and thus one ->probe() function.

Moving the ->init() callback to the mmci_host_ops structure, doesn't
really makes sense to me, as in principle that would requires us to
have separate drivers, which during probe then would call common mmci
library function to register their ops.

We can do this as well, but I didn't want to move that far in these early steps.

What do you think?

>

> If you think it's hairy to dereference twice like mmci->variant->ops(foo)

> you can always copy the pointer mmci->ops = variant->ops and

> be done with it.


Sure, but as stated above, that was not the reason.

>

> It's easy to just assign it directly in the variant data that way:

>

> variant_foo = {

>     (...)

>     .ops = {

>            .init = ...

>


Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij July 16, 2018, 1:12 p.m. | #4
On Mon, Jul 16, 2018 at 12:40 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 13 July 2018 at 17:12, Linus Walleij <linus.walleij@linaro.org> wrote:

> > On Fri, Jul 13, 2018 at 1:15 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> >

> >> To be able to better support different mmci variants, we need to be able to

> >> use variant specific callbacks, rather than continue to sprinkle the code

> >> with additional variant data. To move in this direction, let's add an

> >> optional ->init() callback to the variant data struct, which variants shall

> >> use to assign the mmci_host_ops pointer.

> >>

> >> Using an ->init() callback enables us to partition the code between

> >> different files. To allow separate mmci variant files to implement the

> >> variant specifics, let's also move the definition of the struct

> >> variant_data to the common mmci header file.

> >>

> >> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

> >

> > Good idea!

>

> Thanks!

>

> >

> >> +       if (variant->init)

> >> +               variant->init(host);

> > (...)

> >> +struct variant_data {

> > (...)

> >> +       void (*init)(struct mmci_host *host);

> >> +};

> >> +

> >> +/* mmci variant callbacks */

> >> +struct mmci_host_ops {

> >> +};

> >

> > Why not have the .init() callback inside the struct mmci_host_ops vtable?

>

> The idea is to let the ->init() callback to be assigned at compilation

> time and couple it with the amba_id. In that way, we can keep having

> one common driver and thus one ->probe() function.

>

> Moving the ->init() callback to the mmci_host_ops structure, doesn't

> really makes sense to me, as in principle that would requires us to

> have separate drivers, which during probe then would call common mmci

> library function to register their ops.

>

> We can do this as well, but I didn't want to move that far in these early steps.


Sure go ahead like this, it  is anyway much better than before.
If I have different ideas afterwards, I'll just send a patch :D
Acked-by: Linus Walleij <linus.walleij@linaro.org>


Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f1849775e47e..e907a0a866da 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -48,78 +48,6 @@ 
 
 static unsigned int fmax = 515633;
 
-/**
- * struct variant_data - MMCI variant-specific quirks
- * @clkreg: default value for MCICLOCK register
- * @clkreg_enable: enable value for MMCICLOCK register
- * @clkreg_8bit_bus_enable: enable value for 8 bit bus
- * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
- * @datalength_bits: number of bits in the MMCIDATALENGTH register
- * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
- *	      is asserted (likewise for RX)
- * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
- *		  is asserted (likewise for RX)
- * @data_cmd_enable: enable value for data commands.
- * @st_sdio: enable ST specific SDIO logic
- * @st_clkdiv: true if using a ST-specific clock divider algorithm
- * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
- * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
- * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
- *		     register
- * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @pwrreg_powerup: power up value for MMCIPOWER register
- * @f_max: maximum clk frequency supported by the controller.
- * @signal_direction: input/out direction of bus signals can be indicated
- * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
- * @busy_detect: true if the variant supports busy detection on DAT0.
- * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
- * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
- *		      indicating that the card is busy
- * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
- *		      getting busy end detection interrupts
- * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
- * @explicit_mclk_control: enable explicit mclk control in driver.
- * @qcom_fifo: enables qcom specific fifo pio read logic.
- * @qcom_dml: enables qcom specific dma glue for dma transfers.
- * @reversed_irq_handling: handle data irq before cmd irq.
- * @mmcimask1: true if variant have a MMCIMASK1 register.
- * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
- *	       register.
- * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
- */
-struct variant_data {
-	unsigned int		clkreg;
-	unsigned int		clkreg_enable;
-	unsigned int		clkreg_8bit_bus_enable;
-	unsigned int		clkreg_neg_edge_enable;
-	unsigned int		datalength_bits;
-	unsigned int		fifosize;
-	unsigned int		fifohalfsize;
-	unsigned int		data_cmd_enable;
-	unsigned int		datactrl_mask_ddrmode;
-	unsigned int		datactrl_mask_sdio;
-	bool			st_sdio;
-	bool			st_clkdiv;
-	bool			blksz_datactrl16;
-	bool			blksz_datactrl4;
-	u32			pwrreg_powerup;
-	u32			f_max;
-	bool			signal_direction;
-	bool			pwrreg_clkgate;
-	bool			busy_detect;
-	u32			busy_dpsm_flag;
-	u32			busy_detect_flag;
-	u32			busy_detect_mask;
-	bool			pwrreg_nopower;
-	bool			explicit_mclk_control;
-	bool			qcom_fifo;
-	bool			qcom_dml;
-	bool			reversed_irq_handling;
-	bool			mmcimask1;
-	u32			start_err;
-	u32			opendrain;
-};
-
 static struct variant_data variant_arm = {
 	.fifosize		= 16 * 4,
 	.fifohalfsize		= 8 * 4,
@@ -1706,6 +1634,9 @@  static int mmci_probe(struct amba_device *dev,
 		goto clk_disable;
 	}
 
+	if (variant->init)
+		variant->init(host);
+
 	/*
 	 * The ARM and ST versions of the block have slightly different
 	 * clock divider equations which means that the minimum divider
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index f91cdf7f6dae..f2eff0cc6934 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -195,8 +195,85 @@ 
 #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
 
 struct clk;
-struct variant_data;
 struct dma_chan;
+struct mmci_host;
+
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @clkreg_8bit_bus_enable: enable value for 8 bit bus
+ * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ *	      is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ *		  is asserted (likewise for RX)
+ * @data_cmd_enable: enable value for data commands.
+ * @st_sdio: enable ST specific SDIO logic
+ * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
+ * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
+ *		     register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @f_max: maximum clk frequency supported by the controller.
+ * @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if the variant supports busy detection on DAT0.
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
+ *		      indicating that the card is busy
+ * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
+ *		      getting busy end detection interrupts
+ * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
+ * @explicit_mclk_control: enable explicit mclk control in driver.
+ * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
+ * @reversed_irq_handling: handle data irq before cmd irq.
+ * @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
+ *	       register.
+ * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ */
+struct variant_data {
+	unsigned int		clkreg;
+	unsigned int		clkreg_enable;
+	unsigned int		clkreg_8bit_bus_enable;
+	unsigned int		clkreg_neg_edge_enable;
+	unsigned int		datalength_bits;
+	unsigned int		fifosize;
+	unsigned int		fifohalfsize;
+	unsigned int		data_cmd_enable;
+	unsigned int		datactrl_mask_ddrmode;
+	unsigned int		datactrl_mask_sdio;
+	bool			st_sdio;
+	bool			st_clkdiv;
+	bool			blksz_datactrl16;
+	bool			blksz_datactrl4;
+	u32			pwrreg_powerup;
+	u32			f_max;
+	bool			signal_direction;
+	bool			pwrreg_clkgate;
+	bool			busy_detect;
+	u32			busy_dpsm_flag;
+	u32			busy_detect_flag;
+	u32			busy_detect_mask;
+	bool			pwrreg_nopower;
+	bool			explicit_mclk_control;
+	bool			qcom_fifo;
+	bool			qcom_dml;
+	bool			reversed_irq_handling;
+	bool			mmcimask1;
+	u32			start_err;
+	u32			opendrain;
+	void (*init)(struct mmci_host *host);
+};
+
+/* mmci variant callbacks */
+struct mmci_host_ops {
+};
 
 struct mmci_host_next {
 	struct dma_async_tx_descriptor	*dma_desc;
@@ -228,6 +305,7 @@  struct mmci_host {
 	u32			mask1_reg;
 	bool			vqmmc_enabled;
 	struct mmci_platform_data *plat;
+	struct mmci_host_ops	*ops;
 	struct variant_data	*variant;
 	struct pinctrl		*pinctrl;
 	struct pinctrl_state	*pins_default;