mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-10 09:45:30 +07:00
![Linus Walleij](/assets/img/avatar_default.png)
This converts the two Freescale i.MX SPI drivers Freescale i.MX (CONFIG_SPI_IMX) and Freescale i.MX LPSPI (CONFIG_SPI_FSL_LPSPI) to use GPIO descriptors handled in the SPI core for GPIO chip selects whether defined in the device tree or a board file. The reason why both are converted at the same time is that they were both using the same platform data and platform device population helpers when using board files intertwining the code so this gives a cleaner cut. The platform device creation was passing a platform data container from each boardfile down to the driver using struct spi_imx_master from <linux/platform_data/spi-imx.h>, but this was only conveying the number of chipselects and an int * array of the chipselect GPIO numbers. The imx27 and imx31 platforms had code passing the now-unused platform data when creating the platform devices, this has been repurposed to pass around GPIO descriptor tables. The platform data struct that was just passing an array of integers and number of chip selects for the GPIO lines has been removed. The number of chipselects used to be passed from the board file, because this number also limits the number of native chipselects that the platform can use. To deal with this we just augment the i.MX (CONFIG_SPI_IMX) driver to support 3 chipselects if the platform does not define "num-cs" as a device property (such as from the device tree). This covers all the legacy boards as these use <= 3 native chip selects (or GPIO lines, and in that case the number of chip selects is determined by the core from the number of available GPIO lines). Any new boards should use device tree, so this is a reasonable simplification to cover all old boards. The LPSPI driver never assigned the number of chipselects and thus always fall back to the core default of 1 chip select if no GPIOs are defined in the device tree. The Freescale i.MX driver was already partly utilizing the SPI core to obtain the GPIO numbers from the device tree, so this completes the transtion to let the core handle all of it. All board files and the core i.MX boardfile registration code is augmented to account for these changes. This has been compile-tested with the imx_v4_v5_defconfig and the imx_v6_v7_defconfig. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Shawn Guo <shawnguo@kernel.org> Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Cc: Robin Gong <yibin.gong@nxp.com> Cc: Trent Piepho <tpiepho@impinj.com> Cc: Clark Wang <xiaoning.wang@nxp.com> Cc: Shawn Guo <shawnguo@kernel.org> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Pengutronix Kernel Team <kernel@pengutronix.de> Cc: Fabio Estevam <festevam@gmail.com> Cc: NXP Linux Team <linux-imx@nxp.com> Link: https://lore.kernel.org/r/20200625200252.207614-1-linus.walleij@linaro.org Signed-off-by: Mark Brown <broonie@kernel.org>
427 lines
9.6 KiB
C
427 lines
9.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
|
|
* Copyright (C) 2009 Sascha Hauer (kernel@pengutronix.de)
|
|
*/
|
|
|
|
#include <linux/platform_device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/property.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/eeprom.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/gpio/machine.h>
|
|
#include <linux/usb/otg.h>
|
|
#include <linux/usb/ulpi.h>
|
|
|
|
#include <asm/mach/arch.h>
|
|
#include <asm/mach-types.h>
|
|
#include <asm/mach/time.h>
|
|
|
|
#include "common.h"
|
|
#include "devices-imx27.h"
|
|
#include "ehci.h"
|
|
#include "hardware.h"
|
|
#include "iomux-mx27.h"
|
|
#include "ulpi.h"
|
|
|
|
#define OTG_PHY_CS_GPIO (GPIO_PORTB + 23)
|
|
#define USBH2_PHY_CS_GPIO (GPIO_PORTB + 24)
|
|
#define SPI1_SS0 (GPIO_PORTD + 28)
|
|
#define SPI1_SS1 (GPIO_PORTD + 27)
|
|
#define SD2_CD (GPIO_PORTC + 29)
|
|
|
|
static const int pca100_pins[] __initconst = {
|
|
/* UART1 */
|
|
PE12_PF_UART1_TXD,
|
|
PE13_PF_UART1_RXD,
|
|
PE14_PF_UART1_CTS,
|
|
PE15_PF_UART1_RTS,
|
|
/* SDHC */
|
|
PB4_PF_SD2_D0,
|
|
PB5_PF_SD2_D1,
|
|
PB6_PF_SD2_D2,
|
|
PB7_PF_SD2_D3,
|
|
PB8_PF_SD2_CMD,
|
|
PB9_PF_SD2_CLK,
|
|
SD2_CD | GPIO_GPIO | GPIO_IN,
|
|
/* FEC */
|
|
PD0_AIN_FEC_TXD0,
|
|
PD1_AIN_FEC_TXD1,
|
|
PD2_AIN_FEC_TXD2,
|
|
PD3_AIN_FEC_TXD3,
|
|
PD4_AOUT_FEC_RX_ER,
|
|
PD5_AOUT_FEC_RXD1,
|
|
PD6_AOUT_FEC_RXD2,
|
|
PD7_AOUT_FEC_RXD3,
|
|
PD8_AF_FEC_MDIO,
|
|
PD9_AIN_FEC_MDC,
|
|
PD10_AOUT_FEC_CRS,
|
|
PD11_AOUT_FEC_TX_CLK,
|
|
PD12_AOUT_FEC_RXD0,
|
|
PD13_AOUT_FEC_RX_DV,
|
|
PD14_AOUT_FEC_RX_CLK,
|
|
PD15_AOUT_FEC_COL,
|
|
PD16_AIN_FEC_TX_ER,
|
|
PF23_AIN_FEC_TX_EN,
|
|
/* SSI1 */
|
|
PC20_PF_SSI1_FS,
|
|
PC21_PF_SSI1_RXD,
|
|
PC22_PF_SSI1_TXD,
|
|
PC23_PF_SSI1_CLK,
|
|
/* onboard I2C */
|
|
PC5_PF_I2C2_SDA,
|
|
PC6_PF_I2C2_SCL,
|
|
/* external I2C */
|
|
PD17_PF_I2C_DATA,
|
|
PD18_PF_I2C_CLK,
|
|
/* SPI1 */
|
|
PD25_PF_CSPI1_RDY,
|
|
PD29_PF_CSPI1_SCLK,
|
|
PD30_PF_CSPI1_MISO,
|
|
PD31_PF_CSPI1_MOSI,
|
|
/* OTG */
|
|
OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT,
|
|
PC7_PF_USBOTG_DATA5,
|
|
PC8_PF_USBOTG_DATA6,
|
|
PC9_PF_USBOTG_DATA0,
|
|
PC10_PF_USBOTG_DATA2,
|
|
PC11_PF_USBOTG_DATA1,
|
|
PC12_PF_USBOTG_DATA4,
|
|
PC13_PF_USBOTG_DATA3,
|
|
PE0_PF_USBOTG_NXT,
|
|
PE1_PF_USBOTG_STP,
|
|
PE2_PF_USBOTG_DIR,
|
|
PE24_PF_USBOTG_CLK,
|
|
PE25_PF_USBOTG_DATA7,
|
|
/* USBH2 */
|
|
USBH2_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT,
|
|
PA0_PF_USBH2_CLK,
|
|
PA1_PF_USBH2_DIR,
|
|
PA2_PF_USBH2_DATA7,
|
|
PA3_PF_USBH2_NXT,
|
|
PA4_PF_USBH2_STP,
|
|
PD19_AF_USBH2_DATA4,
|
|
PD20_AF_USBH2_DATA3,
|
|
PD21_AF_USBH2_DATA6,
|
|
PD22_AF_USBH2_DATA0,
|
|
PD23_AF_USBH2_DATA2,
|
|
PD24_AF_USBH2_DATA1,
|
|
PD26_AF_USBH2_DATA5,
|
|
/* display */
|
|
PA5_PF_LSCLK,
|
|
PA6_PF_LD0,
|
|
PA7_PF_LD1,
|
|
PA8_PF_LD2,
|
|
PA9_PF_LD3,
|
|
PA10_PF_LD4,
|
|
PA11_PF_LD5,
|
|
PA12_PF_LD6,
|
|
PA13_PF_LD7,
|
|
PA14_PF_LD8,
|
|
PA15_PF_LD9,
|
|
PA16_PF_LD10,
|
|
PA17_PF_LD11,
|
|
PA18_PF_LD12,
|
|
PA19_PF_LD13,
|
|
PA20_PF_LD14,
|
|
PA21_PF_LD15,
|
|
PA22_PF_LD16,
|
|
PA23_PF_LD17,
|
|
PA26_PF_PS,
|
|
PA28_PF_HSYNC,
|
|
PA29_PF_VSYNC,
|
|
PA31_PF_OE_ACD,
|
|
/* free GPIO */
|
|
GPIO_PORTC | 31 | GPIO_GPIO | GPIO_IN, /* GPIO0_IRQ */
|
|
GPIO_PORTC | 25 | GPIO_GPIO | GPIO_IN, /* GPIO1_IRQ */
|
|
GPIO_PORTE | 5 | GPIO_GPIO | GPIO_IN, /* GPIO2_IRQ */
|
|
};
|
|
|
|
static const struct imxuart_platform_data uart_pdata __initconst = {
|
|
.flags = IMXUART_HAVE_RTSCTS,
|
|
};
|
|
|
|
static const struct mxc_nand_platform_data
|
|
pca100_nand_board_info __initconst = {
|
|
.width = 1,
|
|
.hw_ecc = 1,
|
|
};
|
|
|
|
static const struct imxi2c_platform_data pca100_i2c1_data __initconst = {
|
|
.bitrate = 100000,
|
|
};
|
|
|
|
static const struct property_entry board_eeprom_properties[] = {
|
|
PROPERTY_ENTRY_U32("pagesize", 32),
|
|
{ }
|
|
};
|
|
|
|
static struct i2c_board_info pca100_i2c_devices[] = {
|
|
{
|
|
I2C_BOARD_INFO("24c32", 0x52), /* E0=0, E1=1, E2=0 */
|
|
.properties = board_eeprom_properties,
|
|
}, {
|
|
I2C_BOARD_INFO("pcf8563", 0x51),
|
|
}, {
|
|
I2C_BOARD_INFO("lm75", 0x4a),
|
|
}
|
|
};
|
|
|
|
static struct spi_eeprom at25320 = {
|
|
.name = "at25320an",
|
|
.byte_len = 4096,
|
|
.page_size = 32,
|
|
.flags = EE_ADDR2,
|
|
};
|
|
|
|
static struct spi_board_info pca100_spi_board_info[] __initdata = {
|
|
{
|
|
.modalias = "at25",
|
|
.max_speed_hz = 30000,
|
|
.bus_num = 0,
|
|
.chip_select = 1,
|
|
.platform_data = &at25320,
|
|
},
|
|
};
|
|
|
|
static struct gpiod_lookup_table pca100_spi0_gpiod_table = {
|
|
.dev_id = "imx27-cspi.0", /* Actual device name for spi0 */
|
|
.table = {
|
|
/*
|
|
* The i.MX27 has the i.MX21 GPIO controller, port D is
|
|
* bank 3 and thus named "imx21-gpio.3".
|
|
* SPI1_SS0 is GPIO_PORTD + 28
|
|
* SPI1_SS1 is GPIO_PORTD + 27
|
|
*/
|
|
GPIO_LOOKUP_IDX("imx21-gpio.3", 28, "cs", 0, GPIO_ACTIVE_LOW),
|
|
GPIO_LOOKUP_IDX("imx21-gpio.3", 27, "cs", 1, GPIO_ACTIVE_LOW),
|
|
{ },
|
|
},
|
|
};
|
|
|
|
static void pca100_ac97_warm_reset(struct snd_ac97 *ac97)
|
|
{
|
|
mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT);
|
|
gpio_set_value(GPIO_PORTC + 20, 1);
|
|
udelay(2);
|
|
gpio_set_value(GPIO_PORTC + 20, 0);
|
|
mxc_gpio_mode(PC20_PF_SSI1_FS);
|
|
msleep(2);
|
|
}
|
|
|
|
static void pca100_ac97_cold_reset(struct snd_ac97 *ac97)
|
|
{
|
|
mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT); /* FS */
|
|
gpio_set_value(GPIO_PORTC + 20, 0);
|
|
mxc_gpio_mode(GPIO_PORTC | 22 | GPIO_GPIO | GPIO_OUT); /* TX */
|
|
gpio_set_value(GPIO_PORTC + 22, 0);
|
|
mxc_gpio_mode(GPIO_PORTC | 28 | GPIO_GPIO | GPIO_OUT); /* reset */
|
|
gpio_set_value(GPIO_PORTC + 28, 0);
|
|
udelay(10);
|
|
gpio_set_value(GPIO_PORTC + 28, 1);
|
|
mxc_gpio_mode(PC20_PF_SSI1_FS);
|
|
mxc_gpio_mode(PC22_PF_SSI1_TXD);
|
|
msleep(2);
|
|
}
|
|
|
|
static const struct imx_ssi_platform_data pca100_ssi_pdata __initconst = {
|
|
.ac97_reset = pca100_ac97_cold_reset,
|
|
.ac97_warm_reset = pca100_ac97_warm_reset,
|
|
.flags = IMX_SSI_USE_AC97,
|
|
};
|
|
|
|
static int pca100_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
|
|
void *data)
|
|
{
|
|
int ret;
|
|
|
|
ret = request_irq(gpio_to_irq(IMX_GPIO_NR(3, 29)), detect_irq,
|
|
IRQF_TRIGGER_FALLING, "imx-mmc-detect", data);
|
|
if (ret)
|
|
printk(KERN_ERR
|
|
"pca100: Failed to request irq for sd/mmc detection\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void pca100_sdhc2_exit(struct device *dev, void *data)
|
|
{
|
|
free_irq(gpio_to_irq(IMX_GPIO_NR(3, 29)), data);
|
|
}
|
|
|
|
static const struct imxmmc_platform_data sdhc_pdata __initconst = {
|
|
.init = pca100_sdhc2_init,
|
|
.exit = pca100_sdhc2_exit,
|
|
};
|
|
|
|
static int otg_phy_init(struct platform_device *pdev)
|
|
{
|
|
gpio_set_value(OTG_PHY_CS_GPIO, 0);
|
|
|
|
mdelay(10);
|
|
|
|
return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
|
|
}
|
|
|
|
static struct mxc_usbh_platform_data otg_pdata __initdata = {
|
|
.init = otg_phy_init,
|
|
.portsc = MXC_EHCI_MODE_ULPI,
|
|
};
|
|
|
|
static int usbh2_phy_init(struct platform_device *pdev)
|
|
{
|
|
gpio_set_value(USBH2_PHY_CS_GPIO, 0);
|
|
|
|
mdelay(10);
|
|
|
|
return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
|
|
}
|
|
|
|
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
|
|
.init = usbh2_phy_init,
|
|
.portsc = MXC_EHCI_MODE_ULPI,
|
|
};
|
|
|
|
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
|
|
.operating_mode = FSL_USB2_DR_DEVICE,
|
|
.phy_mode = FSL_USB2_PHY_ULPI,
|
|
};
|
|
|
|
static bool otg_mode_host __initdata;
|
|
|
|
static int __init pca100_otg_mode(char *options)
|
|
{
|
|
if (!strcmp(options, "host"))
|
|
otg_mode_host = true;
|
|
else if (!strcmp(options, "device"))
|
|
otg_mode_host = false;
|
|
else
|
|
pr_info("otg_mode neither \"host\" nor \"device\". "
|
|
"Defaulting to device\n");
|
|
return 1;
|
|
}
|
|
__setup("otg_mode=", pca100_otg_mode);
|
|
|
|
/* framebuffer info */
|
|
static struct imx_fb_videomode pca100_fb_modes[] = {
|
|
{
|
|
.mode = {
|
|
.name = "EMERGING-ETV570G0DHU",
|
|
.refresh = 60,
|
|
.xres = 640,
|
|
.yres = 480,
|
|
.pixclock = 39722, /* in ps (25.175 MHz) */
|
|
.hsync_len = 30,
|
|
.left_margin = 114,
|
|
.right_margin = 16,
|
|
.vsync_len = 3,
|
|
.upper_margin = 32,
|
|
.lower_margin = 0,
|
|
},
|
|
/*
|
|
* TFT
|
|
* Pixel pol active high
|
|
* HSYNC active low
|
|
* VSYNC active low
|
|
* use HSYNC for ACD count
|
|
* line clock disable while idle
|
|
* always enable line clock even if no data
|
|
*/
|
|
.pcr = 0xf0c08080,
|
|
.bpp = 16,
|
|
},
|
|
};
|
|
|
|
static const struct imx_fb_platform_data pca100_fb_data __initconst = {
|
|
.mode = pca100_fb_modes,
|
|
.num_modes = ARRAY_SIZE(pca100_fb_modes),
|
|
|
|
.pwmr = 0x00A903FF,
|
|
.lscr1 = 0x00120300,
|
|
.dmacr = 0x00020010,
|
|
};
|
|
|
|
static void __init pca100_init(void)
|
|
{
|
|
int ret;
|
|
|
|
imx27_soc_init();
|
|
|
|
ret = mxc_gpio_setup_multiple_pins(pca100_pins,
|
|
ARRAY_SIZE(pca100_pins), "PCA100");
|
|
if (ret)
|
|
printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
|
|
|
|
imx27_add_imx_uart0(&uart_pdata);
|
|
|
|
imx27_add_mxc_nand(&pca100_nand_board_info);
|
|
|
|
/* only the i2c master 1 is used on this CPU card */
|
|
i2c_register_board_info(1, pca100_i2c_devices,
|
|
ARRAY_SIZE(pca100_i2c_devices));
|
|
|
|
imx27_add_imx_i2c(1, &pca100_i2c1_data);
|
|
|
|
mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN);
|
|
mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN);
|
|
spi_register_board_info(pca100_spi_board_info,
|
|
ARRAY_SIZE(pca100_spi_board_info));
|
|
imx27_add_spi_imx0(&pca100_spi0_gpiod_table);
|
|
|
|
imx27_add_imx_fb(&pca100_fb_data);
|
|
|
|
imx27_add_fec(NULL);
|
|
imx27_add_imx2_wdt();
|
|
imx27_add_mxc_w1();
|
|
}
|
|
|
|
static void __init pca100_late_init(void)
|
|
{
|
|
imx27_add_imx_ssi(0, &pca100_ssi_pdata);
|
|
|
|
imx27_add_mxc_mmc(1, &sdhc_pdata);
|
|
|
|
gpio_request(OTG_PHY_CS_GPIO, "usb-otg-cs");
|
|
gpio_direction_output(OTG_PHY_CS_GPIO, 1);
|
|
gpio_request(USBH2_PHY_CS_GPIO, "usb-host2-cs");
|
|
gpio_direction_output(USBH2_PHY_CS_GPIO, 1);
|
|
|
|
if (otg_mode_host) {
|
|
otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
|
|
ULPI_OTG_DRVVBUS_EXT);
|
|
|
|
if (otg_pdata.otg)
|
|
imx27_add_mxc_ehci_otg(&otg_pdata);
|
|
} else {
|
|
gpio_set_value(OTG_PHY_CS_GPIO, 0);
|
|
imx27_add_fsl_usb2_udc(&otg_device_pdata);
|
|
}
|
|
|
|
usbh2_pdata.otg = imx_otg_ulpi_create(
|
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
|
|
|
if (usbh2_pdata.otg)
|
|
imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
|
|
}
|
|
|
|
static void __init pca100_timer_init(void)
|
|
{
|
|
mx27_clocks_init(26000000);
|
|
}
|
|
|
|
MACHINE_START(PCA100, "phyCARD-i.MX27")
|
|
.atag_offset = 0x100,
|
|
.map_io = mx27_map_io,
|
|
.init_early = imx27_init_early,
|
|
.init_irq = mx27_init_irq,
|
|
.init_machine = pca100_init,
|
|
.init_late = pca100_late_init,
|
|
.init_time = pca100_timer_init,
|
|
.restart = mxc_restart,
|
|
MACHINE_END
|