ARM: davinci: mmc: derive version information from device name
Remove specifying mmc controller IP version information via platform data, instead specify device name so that driver derives it from platform_device_id table. Also change the clock node name to match the changed dev_id. Tested on da850-evm to make sure driver loads without clk_get failures. Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com> Reviewed-by: Sekhar Nori <nsekhar@ti.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Chris Ball <cjb@laptop.org> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
This commit is contained in:
parent
bb170e6118
commit
d7ca4c755a
|
@ -246,7 +246,6 @@ static struct davinci_mmc_config da830_evm_mmc_config = {
|
||||||
.wires = 8,
|
.wires = 8,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void da830_evm_init_mmc(void)
|
static inline void da830_evm_init_mmc(void)
|
||||||
|
|
|
@ -802,7 +802,6 @@ static struct davinci_mmc_config da850_mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const short da850_evm_mmcsd0_pins[] __initconst = {
|
static const short da850_evm_mmcsd0_pins[] __initconst = {
|
||||||
|
@ -1372,7 +1371,6 @@ static struct davinci_mmc_config da850_wl12xx_mmc_config = {
|
||||||
.max_freq = 25000000,
|
.max_freq = 25000000,
|
||||||
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NONREMOVABLE |
|
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NONREMOVABLE |
|
||||||
MMC_CAP_POWER_OFF_CARD,
|
MMC_CAP_POWER_OFF_CARD,
|
||||||
.version = MMC_CTLR_VERSION_2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const short da850_wl12xx_pins[] __initconst = {
|
static const short da850_wl12xx_pins[] __initconst = {
|
||||||
|
|
|
@ -280,7 +280,6 @@ static struct davinci_mmc_config dm355evm_mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Don't connect anything to J10 unless you're only using USB host
|
/* Don't connect anything to J10 unless you're only using USB host
|
||||||
|
|
|
@ -253,7 +253,6 @@ static struct davinci_mmc_config dm365evm_mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dm365evm_emac_configure(void)
|
static void dm365evm_emac_configure(void)
|
||||||
|
|
|
@ -570,7 +570,6 @@ static struct davinci_mmc_config dm6446evm_mmc_config = {
|
||||||
.get_cd = dm6444evm_mmc_get_cd,
|
.get_cd = dm6444evm_mmc_get_cd,
|
||||||
.get_ro = dm6444evm_mmc_get_ro,
|
.get_ro = dm6444evm_mmc_get_ro,
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.version = MMC_CTLR_VERSION_1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct i2c_board_info __initdata i2c_info[] = {
|
static struct i2c_board_info __initdata i2c_info[] = {
|
||||||
|
|
|
@ -164,7 +164,6 @@ static void __init davinci_ntosd2_map_io(void)
|
||||||
|
|
||||||
static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
|
static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.version = MMC_CTLR_VERSION_1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,6 @@ static struct davinci_mmc_config da850_mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static __init void omapl138_hawk_mmc_init(void)
|
static __init void omapl138_hawk_mmc_init(void)
|
||||||
|
|
|
@ -85,7 +85,6 @@ static struct davinci_mmc_config mmc_config = {
|
||||||
.wires = 4,
|
.wires = 4,
|
||||||
.max_freq = 50000000,
|
.max_freq = 50000000,
|
||||||
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
.caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
|
||||||
.version = MMC_CTLR_VERSION_1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const short sdio1_pins[] __initconst = {
|
static const short sdio1_pins[] __initconst = {
|
||||||
|
|
|
@ -394,7 +394,7 @@ static struct clk_lookup da830_clks[] = {
|
||||||
CLK(NULL, "tpcc", &tpcc_clk),
|
CLK(NULL, "tpcc", &tpcc_clk),
|
||||||
CLK(NULL, "tptc0", &tptc0_clk),
|
CLK(NULL, "tptc0", &tptc0_clk),
|
||||||
CLK(NULL, "tptc1", &tptc1_clk),
|
CLK(NULL, "tptc1", &tptc1_clk),
|
||||||
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
|
CLK("da830-mmc.0", NULL, &mmcsd_clk),
|
||||||
CLK(NULL, "uart0", &uart0_clk),
|
CLK(NULL, "uart0", &uart0_clk),
|
||||||
CLK(NULL, "uart1", &uart1_clk),
|
CLK(NULL, "uart1", &uart1_clk),
|
||||||
CLK(NULL, "uart2", &uart2_clk),
|
CLK(NULL, "uart2", &uart2_clk),
|
||||||
|
|
|
@ -463,8 +463,8 @@ static struct clk_lookup da850_clks[] = {
|
||||||
CLK("davinci_emac.1", NULL, &emac_clk),
|
CLK("davinci_emac.1", NULL, &emac_clk),
|
||||||
CLK("davinci-mcasp.0", NULL, &mcasp_clk),
|
CLK("davinci-mcasp.0", NULL, &mcasp_clk),
|
||||||
CLK("da8xx_lcdc.0", "fck", &lcdc_clk),
|
CLK("da8xx_lcdc.0", "fck", &lcdc_clk),
|
||||||
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
|
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
|
||||||
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
|
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
|
||||||
CLK(NULL, "aemif", &aemif_clk),
|
CLK(NULL, "aemif", &aemif_clk),
|
||||||
CLK(NULL, "usb11", &usb11_clk),
|
CLK(NULL, "usb11", &usb11_clk),
|
||||||
CLK(NULL, "usb20", &usb20_clk),
|
CLK(NULL, "usb20", &usb20_clk),
|
||||||
|
|
|
@ -664,7 +664,7 @@ static struct resource da8xx_mmcsd0_resources[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device da8xx_mmcsd0_device = {
|
static struct platform_device da8xx_mmcsd0_device = {
|
||||||
.name = "davinci_mmc",
|
.name = "da830-mmc",
|
||||||
.id = 0,
|
.id = 0,
|
||||||
.num_resources = ARRAY_SIZE(da8xx_mmcsd0_resources),
|
.num_resources = ARRAY_SIZE(da8xx_mmcsd0_resources),
|
||||||
.resource = da8xx_mmcsd0_resources,
|
.resource = da8xx_mmcsd0_resources,
|
||||||
|
@ -701,7 +701,7 @@ static struct resource da850_mmcsd1_resources[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device da850_mmcsd1_device = {
|
static struct platform_device da850_mmcsd1_device = {
|
||||||
.name = "davinci_mmc",
|
.name = "da830-mmc",
|
||||||
.id = 1,
|
.id = 1,
|
||||||
.num_resources = ARRAY_SIZE(da850_mmcsd1_resources),
|
.num_resources = ARRAY_SIZE(da850_mmcsd1_resources),
|
||||||
.resource = da850_mmcsd1_resources,
|
.resource = da850_mmcsd1_resources,
|
||||||
|
|
|
@ -218,7 +218,7 @@ static u64 mmc1_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
|
||||||
static struct platform_device mmc_devices[2] = {
|
static struct platform_device mmc_devices[2] = {
|
||||||
{
|
{
|
||||||
.name = "davinci_mmc",
|
.name = "dm6441-mmc",
|
||||||
.id = 0,
|
.id = 0,
|
||||||
.dev = {
|
.dev = {
|
||||||
.dma_mask = &mmc0_dma_mask,
|
.dma_mask = &mmc0_dma_mask,
|
||||||
|
@ -228,7 +228,7 @@ static struct platform_device mmc_devices[2] = {
|
||||||
.resource = mmc0_resources
|
.resource = mmc0_resources
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "davinci_mmc",
|
.name = "dm6441-mmc",
|
||||||
.id = 1,
|
.id = 1,
|
||||||
.dev = {
|
.dev = {
|
||||||
.dma_mask = &mmc1_dma_mask,
|
.dma_mask = &mmc1_dma_mask,
|
||||||
|
|
|
@ -150,7 +150,7 @@ static struct resource mmcsd0_resources[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device davinci_mmcsd0_device = {
|
static struct platform_device davinci_mmcsd0_device = {
|
||||||
.name = "davinci_mmc",
|
.name = "dm6441-mmc",
|
||||||
.id = 0,
|
.id = 0,
|
||||||
.dev = {
|
.dev = {
|
||||||
.dma_mask = &mmcsd0_dma_mask,
|
.dma_mask = &mmcsd0_dma_mask,
|
||||||
|
@ -187,7 +187,7 @@ static struct resource mmcsd1_resources[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device davinci_mmcsd1_device = {
|
static struct platform_device davinci_mmcsd1_device = {
|
||||||
.name = "davinci_mmc",
|
.name = "dm6441-mmc",
|
||||||
.id = 1,
|
.id = 1,
|
||||||
.dev = {
|
.dev = {
|
||||||
.dma_mask = &mmcsd1_dma_mask,
|
.dma_mask = &mmcsd1_dma_mask,
|
||||||
|
@ -235,6 +235,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
|
||||||
mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
|
mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
|
||||||
SZ_4K - 1;
|
SZ_4K - 1;
|
||||||
mmcsd1_resources[2].start = IRQ_DM365_SDIOINT1;
|
mmcsd1_resources[2].start = IRQ_DM365_SDIOINT1;
|
||||||
|
davinci_mmcsd1_device.name = "da830-mmc";
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -256,6 +257,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
|
||||||
mmcsd0_resources[0].end = DM365_MMCSD0_BASE +
|
mmcsd0_resources[0].end = DM365_MMCSD0_BASE +
|
||||||
SZ_4K - 1;
|
SZ_4K - 1;
|
||||||
mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0;
|
mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0;
|
||||||
|
davinci_mmcsd0_device.name = "da830-mmc";
|
||||||
} else if (cpu_is_davinci_dm644x()) {
|
} else if (cpu_is_davinci_dm644x()) {
|
||||||
/* REVISIT: should this be in board-init code? */
|
/* REVISIT: should this be in board-init code? */
|
||||||
/* Power-on 3.3V IO cells */
|
/* Power-on 3.3V IO cells */
|
||||||
|
|
|
@ -361,8 +361,8 @@ static struct clk_lookup dm355_clks[] = {
|
||||||
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
||||||
CLK("davinci-mcbsp.0", NULL, &asp0_clk),
|
CLK("davinci-mcbsp.0", NULL, &asp0_clk),
|
||||||
CLK("davinci-mcbsp.1", NULL, &asp1_clk),
|
CLK("davinci-mcbsp.1", NULL, &asp1_clk),
|
||||||
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
|
CLK("dm6441-mmc.0", NULL, &mmcsd0_clk),
|
||||||
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
|
CLK("dm6441-mmc.1", NULL, &mmcsd1_clk),
|
||||||
CLK("spi_davinci.0", NULL, &spi0_clk),
|
CLK("spi_davinci.0", NULL, &spi0_clk),
|
||||||
CLK("spi_davinci.1", NULL, &spi1_clk),
|
CLK("spi_davinci.1", NULL, &spi1_clk),
|
||||||
CLK("spi_davinci.2", NULL, &spi2_clk),
|
CLK("spi_davinci.2", NULL, &spi2_clk),
|
||||||
|
|
|
@ -454,8 +454,8 @@ static struct clk_lookup dm365_clks[] = {
|
||||||
CLK(NULL, "uart0", &uart0_clk),
|
CLK(NULL, "uart0", &uart0_clk),
|
||||||
CLK(NULL, "uart1", &uart1_clk),
|
CLK(NULL, "uart1", &uart1_clk),
|
||||||
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
||||||
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
|
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
|
||||||
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
|
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
|
||||||
CLK("spi_davinci.0", NULL, &spi0_clk),
|
CLK("spi_davinci.0", NULL, &spi0_clk),
|
||||||
CLK("spi_davinci.1", NULL, &spi1_clk),
|
CLK("spi_davinci.1", NULL, &spi1_clk),
|
||||||
CLK("spi_davinci.2", NULL, &spi2_clk),
|
CLK("spi_davinci.2", NULL, &spi2_clk),
|
||||||
|
|
|
@ -310,7 +310,7 @@ static struct clk_lookup dm644x_clks[] = {
|
||||||
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
CLK("i2c_davinci.1", NULL, &i2c_clk),
|
||||||
CLK("palm_bk3710", NULL, &ide_clk),
|
CLK("palm_bk3710", NULL, &ide_clk),
|
||||||
CLK("davinci-mcbsp", NULL, &asp_clk),
|
CLK("davinci-mcbsp", NULL, &asp_clk),
|
||||||
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
|
CLK("dm6441-mmc.0", NULL, &mmcsd_clk),
|
||||||
CLK(NULL, "spi", &spi_clk),
|
CLK(NULL, "spi", &spi_clk),
|
||||||
CLK(NULL, "gpio", &gpio_clk),
|
CLK(NULL, "gpio", &gpio_clk),
|
||||||
CLK(NULL, "usb", &usb_clk),
|
CLK(NULL, "usb", &usb_clk),
|
||||||
|
|
|
@ -272,7 +272,7 @@ static struct clk_lookup clks[] = {
|
||||||
CLK("tnetv107x-keypad.0", NULL, &clk_keypad),
|
CLK("tnetv107x-keypad.0", NULL, &clk_keypad),
|
||||||
CLK(NULL, "clk_gpio", &clk_gpio),
|
CLK(NULL, "clk_gpio", &clk_gpio),
|
||||||
CLK(NULL, "clk_mdio", &clk_mdio),
|
CLK(NULL, "clk_mdio", &clk_mdio),
|
||||||
CLK("davinci_mmc.0", NULL, &clk_sdio0),
|
CLK("dm6441-mmc.0", NULL, &clk_sdio0),
|
||||||
CLK(NULL, "uart0", &clk_uart0),
|
CLK(NULL, "uart0", &clk_uart0),
|
||||||
CLK(NULL, "uart1", &clk_uart1),
|
CLK(NULL, "uart1", &clk_uart1),
|
||||||
CLK(NULL, "timer0", &clk_timer0),
|
CLK(NULL, "timer0", &clk_timer0),
|
||||||
|
@ -292,7 +292,7 @@ static struct clk_lookup clks[] = {
|
||||||
CLK(NULL, "clk_system", &clk_system),
|
CLK(NULL, "clk_system", &clk_system),
|
||||||
CLK(NULL, "clk_imcop", &clk_imcop),
|
CLK(NULL, "clk_imcop", &clk_imcop),
|
||||||
CLK(NULL, "clk_spare", &clk_spare),
|
CLK(NULL, "clk_spare", &clk_spare),
|
||||||
CLK("davinci_mmc.1", NULL, &clk_sdio1),
|
CLK("dm6441-mmc.1", NULL, &clk_sdio1),
|
||||||
CLK(NULL, "clk_ddr2_vrst", &clk_ddr2_vrst),
|
CLK(NULL, "clk_ddr2_vrst", &clk_ddr2_vrst),
|
||||||
CLK(NULL, "clk_ddr2_vctl_rst", &clk_ddr2_vctl_rst),
|
CLK(NULL, "clk_ddr2_vctl_rst", &clk_ddr2_vctl_rst),
|
||||||
CLK(NULL, NULL, NULL),
|
CLK(NULL, NULL, NULL),
|
||||||
|
|
|
@ -1157,6 +1157,18 @@ static void __init init_mmcsd_host(struct mmc_davinci_host *host)
|
||||||
mmc_davinci_reset_ctrl(host, 0);
|
mmc_davinci_reset_ctrl(host, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct platform_device_id davinci_mmc_devtype[] = {
|
||||||
|
{
|
||||||
|
.name = "dm6441-mmc",
|
||||||
|
.driver_data = MMC_CTLR_VERSION_1,
|
||||||
|
}, {
|
||||||
|
.name = "da830-mmc",
|
||||||
|
.driver_data = MMC_CTLR_VERSION_2,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(platform, davinci_mmc_devtype);
|
||||||
|
|
||||||
static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct davinci_mmc_config *pdata = pdev->dev.platform_data;
|
struct davinci_mmc_config *pdata = pdev->dev.platform_data;
|
||||||
|
@ -1165,6 +1177,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
||||||
struct resource *r, *mem = NULL;
|
struct resource *r, *mem = NULL;
|
||||||
int ret = 0, irq = 0;
|
int ret = 0, irq = 0;
|
||||||
size_t mem_size;
|
size_t mem_size;
|
||||||
|
const struct platform_device_id *id_entry;
|
||||||
|
|
||||||
/* REVISIT: when we're fully converted, fail if pdata is NULL */
|
/* REVISIT: when we're fully converted, fail if pdata is NULL */
|
||||||
|
|
||||||
|
@ -1237,7 +1250,9 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
||||||
if (pdata && (pdata->wires == 8))
|
if (pdata && (pdata->wires == 8))
|
||||||
mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
|
mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
|
||||||
|
|
||||||
host->version = pdata->version;
|
id_entry = platform_get_device_id(pdev);
|
||||||
|
if (id_entry)
|
||||||
|
host->version = id_entry->driver_data;
|
||||||
|
|
||||||
mmc->ops = &mmc_davinci_ops;
|
mmc->ops = &mmc_davinci_ops;
|
||||||
mmc->f_min = 312500;
|
mmc->f_min = 312500;
|
||||||
|
@ -1408,6 +1423,7 @@ static struct platform_driver davinci_mmcsd_driver = {
|
||||||
.pm = davinci_mmcsd_pm_ops,
|
.pm = davinci_mmcsd_pm_ops,
|
||||||
},
|
},
|
||||||
.remove = __exit_p(davinci_mmcsd_remove),
|
.remove = __exit_p(davinci_mmcsd_remove),
|
||||||
|
.id_table = davinci_mmc_devtype,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init davinci_mmcsd_init(void)
|
static int __init davinci_mmcsd_init(void)
|
||||||
|
|
|
@ -23,9 +23,6 @@ struct davinci_mmc_config {
|
||||||
/* any additional host capabilities: OR'd in to mmc->f_caps */
|
/* any additional host capabilities: OR'd in to mmc->f_caps */
|
||||||
u32 caps;
|
u32 caps;
|
||||||
|
|
||||||
/* Version of the MMC/SD controller */
|
|
||||||
u8 version;
|
|
||||||
|
|
||||||
/* Number of sg segments */
|
/* Number of sg segments */
|
||||||
u8 nr_sg;
|
u8 nr_sg;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue