diff --git a/arch/arm/boards/chumby_falconwing/falconwing.c b/arch/arm/boards/chumby_falconwing/falconwing.c index 0818666..fd5bc4c 100644 --- a/arch/arm/boards/chumby_falconwing/falconwing.c +++ b/arch/arm/boards/chumby_falconwing/falconwing.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -265,42 +266,6 @@ } mem_initcall(falconwing_mem_init); -/** - * Try to register an environment storage on the attached MCI card - * @return 0 on success - * - * We rely on the existence of a usable SD card, already attached to - * our system, to get something like a persistent memory for our environment. - * If this SD card is also the boot media, we can use the second partition - * for our environment purpose (if present!). - */ -static int register_persistant_environment(void) -{ - struct cdev *cdev; - - /* - * The chumby one only has one MCI card socket. - * So, we expect its name as "disk0". - */ - cdev = cdev_by_name("disk0"); - if (cdev == NULL) { - pr_err("No MCI card preset\n"); - return -ENODEV; - } - - /* MCI card is present, also a useable partition on it? */ - cdev = cdev_by_name("disk0.1"); - if (cdev == NULL) { - pr_err("No second partition available\n"); - pr_info("Please create at least a second partition with" - " 256 kiB...512 kiB in size (your choice)\n"); - return -ENODEV; - } - - /* use the full partition as our persistent environment storage */ - return devfs_add_partition("disk0.1", 0, cdev->size, DEVFS_PARTITION_FIXED, "env0"); -} - #define GPIO_USB_HUB_RESET 29 #define GPIO_USB_HUB_POWER 26 @@ -338,9 +303,9 @@ armlinux_set_bootparams((void *)IMX_MEMORY_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_CHUMBY); - rc = register_persistant_environment(); + rc = envfs_register_partition("disk0", 1); if (rc != 0) - printf("Cannot create the 'env0' persistant environment storage (%d)\n", rc); + printf("Cannot create the 'env0' persistent environment storage (%d)\n", rc); return 0; } diff --git a/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c b/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c index b59dbab..1bc20cf 100644 --- a/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c +++ b/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -99,7 +100,7 @@ static int cfa10036_devices_init(void) { - int i; + int i, ret; /* initizalize muxing */ for (i = 0; i < ARRAY_SIZE(cfa10036_pads); i++) @@ -124,6 +125,11 @@ cfa10036_detect_hw(); + ret = envfs_register_partition("disk0", 1); + if (ret != 0) + printf("Cannot create the 'env0' persistent " + "environment storage (%d)\n", ret); + return 0; } device_initcall(cfa10036_devices_init); diff --git a/arch/arm/boards/crystalfontz-cfa10036/env/boot/mmc-ext3 b/arch/arm/boards/crystalfontz-cfa10036/env/boot/mmc-ext3 index 5e508f9..4d830ed 100644 --- a/arch/arm/boards/crystalfontz-cfa10036/env/boot/mmc-ext3 +++ b/arch/arm/boards/crystalfontz-cfa10036/env/boot/mmc-ext3 @@ -5,6 +5,6 @@ exit fi -global.bootm.image="/mnt/disk0.1/zImage-${global.hostname}" -global.bootm.oftree="/mnt/disk0.1/oftree-${global.board.variant}" +global.bootm.image="/mnt/disk0.2/boot/zImage-${global.hostname}" +global.bootm.oftree="/mnt/disk0.2/boot/oftree-${global.board.variant}" global.linux.bootargs.dyn.root="root=/dev/mmcblk0p3 rootfstype=ext3 rootwait" diff --git a/arch/arm/boards/crystalfontz-cfa10036/env/init/automount b/arch/arm/boards/crystalfontz-cfa10036/env/init/automount index 668775d..8fdca7c 100644 --- a/arch/arm/boards/crystalfontz-cfa10036/env/init/automount +++ b/arch/arm/boards/crystalfontz-cfa10036/env/init/automount @@ -5,5 +5,5 @@ exit fi -mkdir -p /mnt/disk0.1 -automount -d /mnt/disk0.1 '[ -e /dev/disk0.1 ] && mount /dev/disk0.1 /mnt/disk0.1' +mkdir -p /mnt/disk0.2 +automount -d /mnt/disk0.2 '[ -e /dev/disk0.2 ] && mount /dev/disk0.2 /mnt/disk0.2' diff --git a/arch/arm/boards/freescale-mx23-evk/mx23-evk.c b/arch/arm/boards/freescale-mx23-evk/mx23-evk.c index 0c5fa4b..76377b1 100644 --- a/arch/arm/boards/freescale-mx23-evk/mx23-evk.c +++ b/arch/arm/boards/freescale-mx23-evk/mx23-evk.c @@ -24,10 +24,13 @@ #include #include #include +#include +#include static struct mxs_mci_platform_data mci_pdata = { - .caps = MMC_MODE_4BIT, + .caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz, .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */ + .f_min = 400000, }; static const uint32_t pad_setup[] = { @@ -41,6 +44,13 @@ SSP1_DETECT | PULLUP(1), }; +#ifdef CONFIG_USB_GADGET_DRIVER_ARC +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, +}; +#endif + static int mx23_evk_mem_init(void) { arm_add_mem_device("ram0", IMX_MEMORY_BASE, 32 * 1024 * 1024); @@ -49,9 +59,48 @@ } mem_initcall(mx23_evk_mem_init); +/** + * Try to register an environment storage on the attached MCI card + * @return 0 on success + * + * We rely on the existence of a usable SD card, already attached to + * our system, to get something like a persistent memory for our environment. + * If this SD card is also the boot media, we can use the second partition + * for our environment purpose (if present!). + */ +static int register_persistant_environment(void) +{ + struct cdev *cdev; + + /* + * The imx23-olinuxino only has one MCI card socket. + * So, we expect its name as "disk0". + */ + cdev = cdev_by_name("disk0"); + if (cdev == NULL) { + pr_err("No MCI card preset\n"); + return -ENODEV; + } + + + + /* MCI card is present, also a useable partition on it? */ + cdev = cdev_by_name("disk0.1"); + if (cdev == NULL) { + pr_err("No second partition available\n"); + pr_info("Please create at least a second partition with" + " 256 kiB...512 kiB in size (your choice)\n"); + return -ENODEV; + } + + /* use the full partition as our persistent environment storage */ + return devfs_add_partition("disk0.1", 0, cdev->size, + DEVFS_PARTITION_FIXED, "env0"); +} + static int mx23_evk_devices_init(void) { - int i; + int i, rc; /* initizalize gpios */ for (i = 0; i < ARRAY_SIZE(pad_setup); i++) @@ -62,9 +111,21 @@ imx_set_ioclk(480000000); /* enable IOCLK to run at the PLL frequency */ imx_set_sspclk(0, 100000000, 1); - add_generic_device("mxs_mci", 0, NULL, IMX_SSP1_BASE, 0, - IORESOURCE_MEM, &mci_pdata); + add_generic_device("mxs_mci", DEVICE_ID_DYNAMIC, NULL, IMX_SSP1_BASE, + 0x8000, IORESOURCE_MEM, &mci_pdata); + + rc = register_persistant_environment(); + if (rc != 0) + printf("Cannot create the 'env0' persistant " + "environment storage (%d)\n", rc); + +#ifdef CONFIG_USB_GADGET_DRIVER_ARC + imx23_usb_phy_enable(); + add_generic_usb_ehci_device(DEVICE_ID_DYNAMIC, IMX_USB_BASE, NULL); + add_generic_device("fsl-udc", DEVICE_ID_DYNAMIC, NULL, IMX_USB_BASE, + 0x200, IORESOURCE_MEM, &usb_pdata); +#endif return 0; } diff --git a/arch/arm/boards/freescale-mx28-evk/mx28-evk.c b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c index 4311473..2e866a3 100644 --- a/arch/arm/boards/freescale-mx28-evk/mx28-evk.c +++ b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -126,6 +127,12 @@ GPMI_ALE | VE_3_3V, GPMI_CLE | VE_3_3V, GPMI_RESETN, /* act as WP, external PU */ + + /* SSP */ + SSP2_D0 | VE_3_3V | PULLUP(1) | STRENGTH(S8MA), /* MISO DO */ + SSP2_D3 | VE_3_3V | PULLUP(1) | STRENGTH(S8MA), /* SS0 !CS */ + SSP2_CMD | VE_3_3V | PULLUP(1) | STRENGTH(S8MA), /* MOSI DIO */ + SSP2_SCK | VE_3_3V | PULLUP(1) | STRENGTH(S8MA), /* CLK */ }; static struct mxs_mci_platform_data mci_pdata = { @@ -225,6 +232,19 @@ } mem_initcall(mx28_evk_mem_init); +static const struct spi_board_info mx28evk_spi_board_info[] = { + { + .name = "m25p80", + /* + * we leave this with the lower frequency + * as the ssp unit otherwise locks up + */ + .max_speed_hz = 32000000, + .bus_num = 2, + .chip_select = 0, + } +}; + static int mx28_evk_devices_init(void) { int i; @@ -235,8 +255,11 @@ /* enable IOCLK0 to run at the PLL frequency */ imx_set_ioclk(0, 480000000); + imx_set_ioclk(1, 320000000); /* run the SSP unit clock at 100 MHz */ imx_set_sspclk(0, 100000000, 1); + /* run the SSP unit 2 clock at 160Mhz */ + imx_set_sspclk(2, 160000000, 1); armlinux_set_bootparams((void *)IMX_MEMORY_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_MX28EVK); @@ -259,6 +282,12 @@ add_generic_device("mxs_nand", 0, NULL, MXS_GPMI_BASE, 0x2000, IORESOURCE_MEM, NULL); + spi_register_board_info(mx28evk_spi_board_info, + ARRAY_SIZE(mx28evk_spi_board_info)); + + add_generic_device("mxs_spi", 2, NULL, IMX_SSP2_BASE, 0x2000, + IORESOURCE_MEM, NULL); + return 0; } device_initcall(mx28_evk_devices_init); diff --git a/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c index 0482638..9620e85 100644 --- a/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c +++ b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -111,46 +112,6 @@ add_generic_usb_ehci_device(DEVICE_ID_DYNAMIC, IMX_USB_BASE, NULL); } -/** - * Try to register an environment storage on the attached MCI card - * @return 0 on success - * - * We rely on the existence of a usable SD card, already attached to - * our system, to get something like a persistent memory for our environment. - * If this SD card is also the boot media, we can use the second partition - * for our environment purpose (if present!). - */ -static int register_persistant_environment(void) -{ - struct cdev *cdev; - - /* - * The imx23-olinuxino only has one MCI card socket. - * So, we expect its name as "disk0". - */ - cdev = cdev_by_name("disk0"); - if (cdev == NULL) { - pr_err("No MCI card preset\n"); - return -ENODEV; - } - - - - /* MCI card is present, also a useable partition on it? */ - cdev = cdev_by_name("disk0.1"); - if (cdev == NULL) { - pr_err("No second partition available\n"); - pr_info("Please create at least a second partition with" - " 256 kiB...512 kiB in size (your choice)\n"); - return -ENODEV; - } - - /* use the full partition as our persistent environment storage */ - return devfs_add_partition("disk0.1", 0, cdev->size, - DEVFS_PARTITION_FIXED, "env0"); -} - - static int imx23_olinuxino_devices_init(void) { int i, rc; @@ -174,9 +135,9 @@ olinuxino_init_usb(); - rc = register_persistant_environment(); + rc = envfs_register_partition("disk0", 1); if (rc != 0) - printf("Cannot create the 'env0' persistant " + printf("Cannot create the 'env0' persistent " "environment storage (%d)\n", rc); return 0; diff --git a/arch/arm/configs/cfa10036_defconfig b/arch/arm/configs/cfa10036_defconfig index c55d50d..277a3ec 100644 --- a/arch/arm/configs/cfa10036_defconfig +++ b/arch/arm/configs/cfa10036_defconfig @@ -39,5 +39,6 @@ CONFIG_MCI=y CONFIG_MCI_STARTUP=y CONFIG_MCI_MXS=y +CONFIG_FS_EXT4=y CONFIG_FS_FAT=y CONFIG_FS_FAT_LFN=y diff --git a/arch/arm/configs/imx23evk_defconfig b/arch/arm/configs/imx23evk_defconfig index 2fc6ebe..1502d22 100644 --- a/arch/arm/configs/imx23evk_defconfig +++ b/arch/arm/configs/imx23evk_defconfig @@ -5,20 +5,29 @@ CONFIG_LONGHELP=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y -# CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y +CONFIG_RESET_SOURCE=y CONFIG_DEBUG_INFO=y CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y CONFIG_CMD_SAVEENV=y -CONFIG_CMD_LOADENV=y CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y CONFIG_CMD_ECHO_E=y +CONFIG_CMD_RESET=y CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y -CONFIG_CMD_RESET=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y # CONFIG_SPI is not set +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_MCI=y +CONFIG_MCI_STARTUP=y +CONFIG_MCI_MXS=y +CONFIG_FS_EXT4=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y diff --git a/arch/arm/mach-mxs/include/mach/ssp.h b/arch/arm/mach-mxs/include/mach/ssp.h new file mode 100644 index 0000000..5eee5c0 --- /dev/null +++ b/arch/arm/mach-mxs/include/mach/ssp.h @@ -0,0 +1,120 @@ +/* + * Freescale MXS SSP + * + * Copyright (C) 2013 Michael Grzeschik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#ifndef __SSP_H__ +#define __SSP_H__ + +#ifdef CONFIG_ARCH_IMX23 +# define HW_SSP_CTRL0 0x000 +# define HW_SSP_CMD0 0x010 +# define HW_SSP_CMD1 0x020 +# define HW_SSP_COMPREF 0x030 +# define HW_SSP_COMPMASK 0x040 +# define HW_SSP_TIMING 0x050 +# define HW_SSP_CTRL1 0x060 +# define HW_SSP_DATA 0x070 +# define HW_SSP_SDRESP0 0x080 +# define HW_SSP_SDRESP1 0x090 +# define HW_SSP_SDRESP2 0x0A0 +# define HW_SSP_SDRESP3 0x0B0 +# define HW_SSP_STATUS 0x0C0 +# define HW_SSP_DEBUG 0x100 +# define HW_SSP_VERSION 0x110 +#endif + +#ifdef CONFIG_ARCH_IMX28 +# define HW_SSP_CTRL0 0x000 +# define HW_SSP_CMD0 0x010 +# define HW_SSP_CMD1 0x020 +# define HW_SSP_XFER_COUNT 0x030 +# define HW_SSP_BLOCK_SIZE 0x040 +# define HW_SSP_COMPREF 0x050 +# define HW_SSP_COMPMASK 0x060 +# define HW_SSP_TIMING 0x070 +# define HW_SSP_CTRL1 0x080 +# define HW_SSP_DATA 0x090 +# define HW_SSP_SDRESP0 0x0A0 +# define HW_SSP_SDRESP1 0x0B0 +# define HW_SSP_SDRESP2 0x0C0 +# define HW_SSP_SDRESP3 0x0D0 +# define HW_SSP_DDR_CTRL 0x0E0 +# define HW_SSP_DLL_CTRL 0x0F0 +# define HW_SSP_STATUS 0x100 +# define HW_SSP_DLL_STS 0x110 +# define HW_SSP_DEBUG 0x120 +# define HW_SSP_VERSION 0x130 +#endif + +#define SSP_CTRL0_SFTRST (1 << 31) +#define SSP_CTRL0_CLKGATE (1 << 30) +#define SSP_CTRL0_RUN (1 << 29) +#define SSP_CTRL0_LOCK_CS (1 << 27) +#define SSP_CTRL0_READ (1 << 25) +#define SSP_CTRL0_IGNORE_CRC (1 << 26) +#define SSP_CTRL0_DATA_XFER (1 << 24) +#define SSP_CTRL0_BUS_WIDTH(x) (((x) & 0x3) << 22) +#define SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) +#define SSP_CTRL0_WAIT_FOR_CMD (1 << 20) +#define SSP_CTRL0_SSP_ASSERT_OUT(x) (((x) & 0x3) << 20) +#define SSP_CTRL0_LONG_RESP (1 << 19) +#define SSP_CTRL0_GET_RESP (1 << 17) +#define SSP_CTRL0_ENABLE (1 << 16) + +#define SSP_CMD0_SLOW_CLK (1 << 22) +#define SSP_CMD0_CONT_CLK (1 << 21) +#define SSP_CMD0_APPEND_8CYC (1 << 20) +#ifdef CONFIG_ARCH_IMX23 +# define SSP_CTRL0_XFER_COUNT(x) ((x) & 0xffff) +# define SSP_CMD0_BLOCK_SIZE(x) (((x) & 0xf) << 16) +# define SSP_CMD0_BLOCK_COUNT(x) (((x) & 0xff) << 8) +#endif +#define SSP_CMD0_CMD(x) ((x) & 0xff) + +#ifdef CONFIG_ARCH_IMX28 +# define SSP_BLOCK_SIZE(x) ((x) & 0xf) +# define SSP_BLOCK_COUNT(x) (((x) & 0xffffff) << 4) +#endif + +/* bit definition for register HW_SSP_TIMING */ +#define SSP_TIMING_TIMEOUT_MASK (0xffff0000) +#define SSP_TIMING_TIMEOUT(x) ((x) << 16) +#define SSP_TIMING_CLOCK_DIVIDE(x) (((x) & 0xff) << 8) +#define SSP_TIMING_CLOCK_RATE(x) ((x) & 0xff) + +/* bit definition for register HW_SSP_CTRL1 */ +#define SSP_CTRL1_POLARITY (1 << 9) +#define SSP_CTRL1_PHASE (1 << 10) +#define SSP_CTRL1_DMA_ENABLE (1 << 13) +#define SSP_CTRL1_WORD_LENGTH(x) (((x) & 0xf) << 4) +#define SSP_CTRL1_SSP_MODE(x) ((x) & 0xf) + +/* bit definition for register HW_SSP_STATUS */ +# define SSP_STATUS_PRESENT (1 << 31) +# define SSP_STATUS_SD_PRESENT (1 << 29) +# define SSP_STATUS_CARD_DETECT (1 << 28) +# define SSP_STATUS_RESP_CRC_ERR (1 << 16) +# define SSP_STATUS_RESP_ERR (1 << 15) +# define SSP_STATUS_RESP_TIMEOUT (1 << 14) +# define SSP_STATUS_DATA_CRC_ERR (1 << 13) +# define SSP_STATUS_TIMEOUT (1 << 12) +# define SSP_STATUS_FIFO_OVRFLW (1 << 9) +# define SSP_STATUS_FIFO_FULL (1 << 8) +# define SSP_STATUS_FIFO_EMPTY (1 << 5) +# define SSP_STATUS_FIFO_UNDRFLW (1 << 4) +# define SSP_STATUS_CMD_BUSY (1 << 3) +# define SSP_STATUS_DATA_BUSY (1 << 2) +# define SSP_STATUS_BUSY (1 << 0) +# define SSP_STATUS_ERROR (SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW | \ + SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR | \ + SSP_STATUS_RESP_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | SSP_STATUS_TIMEOUT) + +#endif /* __SSP_H__ */ diff --git a/common/environment.c b/common/environment.c index e8d623f..78cd45c 100644 --- a/common/environment.c +++ b/common/environment.c @@ -363,3 +363,43 @@ free(buf_free); return ret; } + +#ifdef __BAREBOX__ +/** + * Try to register an environment storage on a device's partition + * @return 0 on success + * + * We rely on the existence of a usable storage device, already attached to + * our system, to get something like a persistent memory for our environment. + * We need to specify the partition number to use on this device. + * @param[in] devname Name of the device + * @param[in] partnr Partition number + * @return 0 on success, anything else in case of failure + */ + +int envfs_register_partition(const char *devname, unsigned int partnr) +{ + struct cdev *cdev; + char *partname; + + if (!devname) + return -EINVAL; + + cdev = cdev_by_name(devname); + if (cdev == NULL) { + pr_err("No %s present\n", devname); + return -ENODEV; + } + partname = asprintf("%s.%d", devname, partnr); + cdev = cdev_by_name(partname); + if (cdev == NULL) { + pr_err("No %s partition available\n", partname); + pr_info("Please create the partition %s to store the env\n", partname); + return -ENODEV; + } + + return devfs_add_partition(partname, 0, cdev->size, + DEVFS_PARTITION_FIXED, "env0"); +} +EXPORT_SYMBOL(envfs_register_partition); +#endif diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c index c65796b..3657b3e 100644 --- a/drivers/mci/mxs.c +++ b/drivers/mci/mxs.c @@ -40,127 +40,11 @@ #include #include #include +#include #define CLOCKRATE_MIN (1 * 1000 * 1000) #define CLOCKRATE_MAX (480 * 1000 * 1000) -#define HW_SSP_CTRL0 0x000 -# define SSP_CTRL0_SFTRST (1 << 31) -# define SSP_CTRL0_CLKGATE (1 << 30) -# define SSP_CTRL0_RUN (1 << 29) -# define SSP_CTRL0_LOCK_CS (1 << 27) -# define SSP_CTRL0_READ (1 << 25) -# define SSP_CTRL0_IGNORE_CRC (1 << 26) -# define SSP_CTRL0_DATA_XFER (1 << 24) -# define SSP_CTRL0_BUS_WIDTH(x) (((x) & 0x3) << 22) -# define SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) -# define SSP_CTRL0_LONG_RESP (1 << 19) -# define SSP_CTRL0_GET_RESP (1 << 17) -# define SSP_CTRL0_ENABLE (1 << 16) -#ifdef CONFIG_ARCH_IMX23 -# define SSP_CTRL0_XFER_COUNT(x) ((x) & 0xffff) -#endif - -#define HW_SSP_CMD0 0x010 -# define SSP_CMD0_SLOW_CLK (1 << 22) -# define SSP_CMD0_CONT_CLK (1 << 21) -# define SSP_CMD0_APPEND_8CYC (1 << 20) -#ifdef CONFIG_ARCH_IMX23 -# define SSP_CMD0_BLOCK_SIZE(x) (((x) & 0xf) << 16) -# define SSP_CMD0_BLOCK_COUNT(x) (((x) & 0xff) << 8) -#endif -# define SSP_CMD0_CMD(x) ((x) & 0xff) - -#define HW_SSP_CMD1 0x020 - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_COMPREF 0x030 -# define HW_SSP_COMPMASK 0x040 -# define HW_SSP_TIMING 0x050 -# define HW_SSP_CTRL1 0x060 -# define HW_SSP_DATA 0x070 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_XFER_COUNT 0x30 -# define HW_SSP_BLOCK_SIZE 0x40 -# define SSP_BLOCK_SIZE(x) ((x) & 0xf) -# define SSP_BLOCK_COUNT(x) (((x) & 0xffffff) << 4) -# define HW_SSP_COMPREF 0x050 -# define HW_SSP_COMPMASK 0x060 -# define HW_SSP_TIMING 0x070 -# define HW_SSP_CTRL1 0x080 -# define HW_SSP_DATA 0x090 -#endif -/* bit definition for register HW_SSP_TIMING */ -# define SSP_TIMING_TIMEOUT_MASK (0xffff0000) -# define SSP_TIMING_TIMEOUT(x) ((x) << 16) -# define SSP_TIMING_CLOCK_DIVIDE(x) (((x) & 0xff) << 8) -# define SSP_TIMING_CLOCK_RATE(x) ((x) & 0xff) - -/* bit definition for register HW_SSP_CTRL1 */ -# define SSP_CTRL1_POLARITY (1 << 9) -# define SSP_CTRL1_WORD_LENGTH(x) (((x) & 0xf) << 4) -# define SSP_CTRL1_SSP_MODE(x) ((x) & 0xf) - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_SDRESP0 0x080 -# define HW_SSP_SDRESP1 0x090 -# define HW_SSP_SDRESP2 0x0A0 -# define HW_SSP_SDRESP3 0x0B0 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_SDRESP0 0x0A0 -# define HW_SSP_SDRESP1 0x0B0 -# define HW_SSP_SDRESP2 0x0C0 -# define HW_SSP_SDRESP3 0x0D0 -#endif - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DDR_CTRL 0x0E0 -# define HW_SSP_DLL_CTRL 0x0F0 -#endif - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_STATUS 0x0C0 -#endif -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_STATUS 0x100 -#endif - -/* bit definition for register HW_SSP_STATUS */ -# define SSP_STATUS_PRESENT (1 << 31) -# define SSP_STATUS_SD_PRESENT (1 << 29) -# define SSP_STATUS_CARD_DETECT (1 << 28) -# define SSP_STATUS_RESP_CRC_ERR (1 << 16) -# define SSP_STATUS_RESP_ERR (1 << 15) -# define SSP_STATUS_RESP_TIMEOUT (1 << 14) -# define SSP_STATUS_DATA_CRC_ERR (1 << 13) -# define SSP_STATUS_TIMEOUT (1 << 12) -# define SSP_STATUS_FIFO_OVRFLW (1 << 9) -# define SSP_STATUS_FIFO_FULL (1 << 8) -# define SSP_STATUS_FIFO_EMPTY (1 << 5) -# define SSP_STATUS_FIFO_UNDRFLW (1 << 4) -# define SSP_STATUS_CMD_BUSY (1 << 3) -# define SSP_STATUS_DATA_BUSY (1 << 2) -# define SSP_STATUS_BUSY (1 << 0) -# define SSP_STATUS_ERROR (SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW | \ - SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR | \ - SSP_STATUS_RESP_TIMEOUT | SSP_STATUS_DATA_CRC_ERR | SSP_STATUS_TIMEOUT) - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DLL_STS 0x110 -#endif - -#ifdef CONFIG_ARCH_IMX23 -# define HW_SSP_DEBUG 0x100 -# define HW_SSP_VERSION 0x110 -#endif - -#ifdef CONFIG_ARCH_IMX28 -# define HW_SSP_DEBUG 0x120 -# define HW_SSP_VERSION 0x130 -#endif - struct mxs_mci_host { struct mci_host host; void __iomem *regs; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index f61d670..48bea60 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -22,7 +22,11 @@ config DRIVER_SERIAL_STM378X depends on ARCH_MXS default y - bool "i.MX23/i.MX28 serial driver" + bool "i.MX23/i.MX28 debug UART serial driver" + +config DRIVER_SERIAL_AUART + depends on ARCH_MXS + bool "i.MX23/i.MX28 application UART serial driver" config DRIVER_SERIAL_NETX depends on ARCH_NETX diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 16a54c2..4a23aef 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_DRIVER_SERIAL_ALTERA_JTAG) += serial_altera_jtag.o obj-$(CONFIG_DRIVER_SERIAL_PXA) += serial_pxa.o obj-$(CONFIG_DRIVER_SERIAL_OMAP4_USBBOOT) += serial_omap4_usbboot.o +obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o diff --git a/drivers/serial/serial_auart.c b/drivers/serial/serial_auart.c new file mode 100644 index 0000000..fa2e04f --- /dev/null +++ b/drivers/serial/serial_auart.c @@ -0,0 +1,238 @@ +/* + * (C) 2013 Marc Kleine-Budde + * + * Based on the stm-serial driver: + * + * (C) Copyright 2010 Juergen Beisert - Pengutronix + * + * ...also based on the u-boot auart driver: + * + * (C) 2011 Wolfgang Ocker + * + * Based on the standard DUART serial driver: + * + * (C) 2007 Sascha Hauer + * + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * Further based on the Linux mxs-auart.c driver: + * + * Freescale STMP37XX/STMP378X Application UART driver + * + * Author: dmitry pervushin + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HW_UARTAPP_CTRL0 (0x00000000) + +#define HW_UARTAPP_CTRL2 (0x00000020) +#define HW_UARTAPP_CTRL2_SET (0x00000024) +#define HW_UARTAPP_CTRL2_CLR (0x00000028) +#define BM_UARTAPP_CTRL2_CTSEN (0x00008000) +#define BM_UARTAPP_CTRL2_RTSEN (0x00004000) +#define BM_UARTAPP_CTRL2_RXE (0x00000200) +#define BM_UARTAPP_CTRL2_TXE (0x00000100) +#define BM_UARTAPP_CTRL2_USE_LCR2 (0x00000040) +#define BM_UARTAPP_CTRL2_UARTEN (0x00000001) + +#define HW_UARTAPP_LINECTRL (0x00000030) +#define BM_UARTAPP_LINECTRL_FEN (0x00000010) + +#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC (0x00003F00) +#define BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(v) \ + (((v) << 8) & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC) + +#define BP_UARTAPP_LINECTRL_BAUD_DIVINT (16) +#define BM_UARTAPP_LINECTRL_BAUD_DIVINT (0xFFFF0000) +#define BF_UARTAPP_LINECTRL_BAUD_DIVINT(v) \ + (((v) << 16) & BM_UARTAPP_LINECTRL_BAUD_DIVINT) + +#define BP_UARTAPP_LINECTRL_WLEN (5) +#define BM_UARTAPP_LINECTRL_WLEN (0x00000060) +#define BF_UARTAPP_LINECTRL_WLEN(v) \ + (((v) << 5) & BM_UARTAPP_LINECTRL_WLEN) + +#define HW_UARTAPP_LINECTRL2_SET (0x00000044) + +#define HW_UARTAPP_INTR (0x00000050) + +#define HW_UARTAPP_DATA (0x00000060) +#define BM_UARTAPP_STAT_RXFE (0x01000000) +#define BM_UARTAPP_STAT_TXFE (0x08000000) + +#define HW_UARTAPP_STAT (0x00000070) +#define BM_UARTAPP_STAT_TXFF (0x02000000) + +struct auart_priv { + struct console_device cdev; + int baudrate; + struct notifier_block notify; + void __iomem *base; +}; + +static void auart_serial_putc(struct console_device *cdev, char c) +{ + struct auart_priv *priv = container_of(cdev, struct auart_priv, cdev); + + /* Wait for room in TX FIFO */ + while (readl(priv->base + HW_UARTAPP_STAT) & BM_UARTAPP_STAT_TXFF) + ; + + writel(c, priv->base + HW_UARTAPP_DATA); +} + +static int auart_serial_tstc(struct console_device *cdev) +{ + struct auart_priv *priv = container_of(cdev, struct auart_priv, cdev); + + /* Check if RX FIFO is not empty */ + return !(readl(priv->base + HW_UARTAPP_STAT) & BM_UARTAPP_STAT_RXFE); +} + +static int auart_serial_getc(struct console_device *cdev) +{ + struct auart_priv *priv = container_of(cdev, struct auart_priv, cdev); + + /* Wait while RX FIFO is empty */ + while (!auart_serial_tstc(cdev)) + ; + + return readl(priv->base + HW_UARTAPP_DATA) & 0xff; +} + +static void auart_serial_flush(struct console_device *cdev) +{ + struct auart_priv *priv = container_of(cdev, struct auart_priv, cdev); + + /* Wait for TX FIFO empty */ + while (readl(priv->base + HW_UARTAPP_STAT) & BM_UARTAPP_STAT_TXFE) + ; +} + +static int auart_serial_setbaudrate(struct console_device *cdev, int new_baudrate) +{ + struct auart_priv *priv = container_of(cdev, struct auart_priv, cdev); + uint32_t ctrl2, quot, reg; + + /* Disable everything */ + ctrl2 = readl(priv->base + HW_UARTAPP_CTRL2); + writel(0x0, priv->base + HW_UARTAPP_CTRL2); + + /* Calculate and set baudrate */ + quot = (imx_get_xclk() * 32) / new_baudrate; + reg = BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(quot & 0x3F) | + BF_UARTAPP_LINECTRL_BAUD_DIVINT(quot >> 6) | + BF_UARTAPP_LINECTRL_WLEN(3) | + BM_UARTAPP_LINECTRL_FEN; + + writel(reg, priv->base + HW_UARTAPP_LINECTRL); + + /* Re-enable UART */ + writel(ctrl2, priv->base + HW_UARTAPP_CTRL2); + + priv->baudrate = new_baudrate; + + return 0; +} + +static int auart_clocksource_clock_change(struct notifier_block *nb, unsigned long event, void *data) +{ + struct auart_priv *priv = container_of(nb, struct auart_priv, notify); + + return auart_serial_setbaudrate(&priv->cdev, priv->baudrate); +} + +static void auart_serial_init_port(struct auart_priv *priv) +{ + mxs_reset_block(priv->base + HW_UARTAPP_CTRL0, 0); + + /* Disable UART */ + writel(0x0, priv->base + HW_UARTAPP_CTRL2); + /* Mask interrupts */ + writel(0x0, priv->base + HW_UARTAPP_INTR); +} + +static int auart_serial_probe(struct device_d *dev) +{ + struct auart_priv *priv; + struct console_device *cdev; + + priv = xzalloc(sizeof *priv); + cdev = &priv->cdev; + + cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; + cdev->tstc = auart_serial_tstc; + cdev->putc = auart_serial_putc; + cdev->getc = auart_serial_getc; + cdev->flush = auart_serial_flush; + cdev->setbrg = auart_serial_setbaudrate; + cdev->dev = dev; + + dev->priv = priv; + priv->base = dev_request_mem_region(dev, 0); + + auart_serial_init_port(priv); + auart_serial_setbaudrate(cdev, CONFIG_BAUDRATE); + + /* Disable RTS/CTS, enable Rx, Tx, UART */ + writel(BM_UARTAPP_CTRL2_RTSEN | BM_UARTAPP_CTRL2_CTSEN | + BM_UARTAPP_CTRL2_USE_LCR2, + priv->base + HW_UARTAPP_CTRL2_CLR); + writel(BM_UARTAPP_CTRL2_RXE | BM_UARTAPP_CTRL2_TXE | + BM_UARTAPP_CTRL2_UARTEN, + priv->base + HW_UARTAPP_CTRL2_SET); + + console_register(cdev); + priv->notify.notifier_call = auart_clocksource_clock_change; + clock_register_client(&priv->notify); + + return 0; +} + + +static void auart_serial_remove(struct device_d *dev) +{ + struct auart_priv *priv = dev->priv; + + auart_serial_flush(&priv->cdev); + console_unregister(&priv->cdev); + free(priv); +} + +static struct driver_d auart_serial_driver = { + .name = "auart_serial", + .probe = auart_serial_probe, + .remove = auart_serial_remove, +}; + +static int auart_serial_init(void) +{ + platform_driver_register(&auart_serial_driver); + return 0; +} + +console_initcall(auart_serial_init); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 10b8fea..f14e28f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -33,6 +33,11 @@ depends on ARCH_IMX51 || ARCH_IMX53 || ARCH_IMX6 default y +config DRIVER_SPI_MXS + bool "i.MX (23,28) SPI Master driver" + depends on ARCH_IMX23 || ARCH_IMX28 + depends on SPI + config DRIVER_SPI_OMAP3 bool "OMAP3 McSPI Master driver" depends on ARCH_OMAP3 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b53061e..642b7ec 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_SPI) += spi.o obj-$(CONFIG_DRIVER_SPI_IMX) += imx_spi.o +obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c new file mode 100644 index 0000000..89b4d19 --- /dev/null +++ b/drivers/spi/mxs_spi.c @@ -0,0 +1,289 @@ +/* + * Freescale i.MX28 SPI driver + * + * Copyright (C) 2013 Michael Grzeschik + * + * Copyright (C) 2011 Marek Vasut + * on behalf of DENX Software Engineering GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXS_SPI_MAX_TIMEOUT (10 * MSECOND) + +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +struct mxs_spi { + struct spi_master master; + uint32_t max_khz; + uint32_t mode; + struct clk *clk; + void __iomem *regs; +}; + +static inline struct mxs_spi *to_mxs(struct spi_master *master) +{ + return container_of(master, struct mxs_spi, master); +} + +/* + * Set SSP/MMC bus frequency, in kHz + */ +static void imx_set_ssp_busclock(struct spi_master *master, uint32_t freq) +{ + struct mxs_spi *mxs = to_mxs(master); + const uint32_t sspclk = imx_get_sspclk(master->bus_num); + uint32_t val; + uint32_t divide, rate, tgtclk; + + /* + * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), + * CLOCK_DIVIDE has to be an even value from 2 to 254, and + * CLOCK_RATE could be any integer from 0 to 255. + */ + for (divide = 2; divide < 254; divide += 2) { + rate = sspclk / freq / divide; + if (rate <= 256) + break; + } + + tgtclk = sspclk / divide / rate; + while (tgtclk > freq) { + rate++; + tgtclk = sspclk / divide / rate; + } + if (rate > 256) + rate = 256; + + /* Always set timeout the maximum */ + val = SSP_TIMING_TIMEOUT_MASK | + SSP_TIMING_CLOCK_DIVIDE(divide) | + SSP_TIMING_CLOCK_RATE(rate - 1); + writel(val, mxs->regs + HW_SSP_TIMING); + + dev_dbg(master->dev, "SPI%d: Set freq rate to %d KHz (requested %d KHz)\n", + master->bus_num, tgtclk, freq); +} + +static int mxs_spi_setup(struct spi_device *spi) +{ + struct spi_master *master = spi->master; + struct mxs_spi *mxs = to_mxs(master); + uint32_t val = 0; + + /* MXS SPI: 4 ports and 3 chip selects maximum */ + if (master->bus_num > 3 || spi->chip_select > 2) { + dev_err(master->dev, "mxs_spi: invalid bus %d / chip select %d\n", + master->bus_num, spi->chip_select); + return -EINVAL; + } + + mxs_reset_block(mxs->regs + HW_SSP_CTRL0, 0); + + val |= SSP_CTRL0_SSP_ASSERT_OUT(spi->chip_select); + val |= SSP_CTRL0_BUS_WIDTH(0); + writel(val, mxs->regs + HW_SSP_CTRL0 + BIT_SET); + + val = SSP_CTRL1_SSP_MODE(0) | SSP_CTRL1_WORD_LENGTH(7); + val |= (mxs->mode & SPI_CPOL) ? SSP_CTRL1_POLARITY : 0; + val |= (mxs->mode & SPI_CPHA) ? SSP_CTRL1_PHASE : 0; + writel(val, mxs->regs + HW_SSP_CTRL1); + + writel(0x0, mxs->regs + HW_SSP_CMD0); + writel(0x0, mxs->regs + HW_SSP_CMD1); + + imx_set_ssp_busclock(master, spi->max_speed_hz); + + return 0; +} + +static void mxs_spi_start_xfer(struct mxs_spi *mxs) +{ + writel(SSP_CTRL0_LOCK_CS, mxs->regs + HW_SSP_CTRL0 + BIT_SET); + writel(SSP_CTRL0_IGNORE_CRC, mxs->regs + HW_SSP_CTRL0 + BIT_CLR); +} + +static void mxs_spi_end_xfer(struct mxs_spi *mxs) +{ + writel(SSP_CTRL0_LOCK_CS, mxs->regs + HW_SSP_CTRL0 + BIT_CLR); + writel(SSP_CTRL0_IGNORE_CRC, mxs->regs + HW_SSP_CTRL0 + BIT_SET); +} + +static void mxs_spi_set_cs(struct spi_device *spi) +{ + struct mxs_spi *mxs = to_mxs(spi->master); + const uint32_t mask = SSP_CTRL0_WAIT_FOR_CMD | SSP_CTRL0_WAIT_FOR_IRQ; + uint32_t select = SSP_CTRL0_SSP_ASSERT_OUT(spi->chip_select); + + writel(mask, mxs->regs + HW_SSP_CTRL0 + BIT_CLR); + writel(select, mxs->regs + HW_SSP_CTRL0 + BIT_SET); +} + +static int mxs_spi_xfer_pio(struct spi_device *spi, + char *data, int length, int write, unsigned long flags) +{ + struct mxs_spi *mxs = to_mxs(spi->master); + struct spi_master *master = spi->master; + + if (flags & SPI_XFER_BEGIN) + mxs_spi_start_xfer(mxs); + + mxs_spi_set_cs(spi); + + while (length--) { + if ((flags & SPI_XFER_END) && !length) + mxs_spi_end_xfer(mxs); + + /* We transfer 1 byte */ + writel(1, mxs->regs + HW_SSP_XFER_COUNT); + + if (write) + writel(SSP_CTRL0_READ, mxs->regs + HW_SSP_CTRL0 + BIT_CLR); + else + writel(SSP_CTRL0_READ, mxs->regs + HW_SSP_CTRL0 + BIT_SET); + + writel(SSP_CTRL0_RUN, mxs->regs + HW_SSP_CTRL0 + BIT_SET); + + if (wait_on_timeout(MXS_SPI_MAX_TIMEOUT, + (readl(mxs->regs + HW_SSP_CTRL0) & SSP_CTRL0_RUN) == SSP_CTRL0_RUN)) { + dev_err(master->dev, "MXS SPI: Timeout waiting for start\n"); + return -ETIMEDOUT; + } + + if (write) + writel(*data++, mxs->regs + HW_SSP_DATA); + + writel(SSP_CTRL0_DATA_XFER, mxs->regs + HW_SSP_CTRL0 + BIT_SET); + + if (!write) { + if (wait_on_timeout(MXS_SPI_MAX_TIMEOUT, + !(readl(mxs->regs + HW_SSP_STATUS) & SSP_STATUS_FIFO_EMPTY))) { + dev_err(master->dev, "MXS SPI: Timeout waiting for data\n"); + return -ETIMEDOUT; + } + + *data++ = readl(mxs->regs + HW_SSP_DATA) & 0xff; + } + + if (wait_on_timeout(MXS_SPI_MAX_TIMEOUT, + !(readl(mxs->regs + HW_SSP_CTRL0) & SSP_CTRL0_RUN))) { + dev_err(master->dev, "MXS SPI: Timeout waiting for finish\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int mxs_spi_transfer(struct spi_device *spi, struct spi_message *mesg) +{ + struct mxs_spi *mxs = to_mxs(spi->master); + struct spi_master *master = spi->master; + struct spi_transfer *t = NULL; + char dummy; + unsigned long flags = 0; + int write = 0; + char *data = NULL; + int ret; + mesg->actual_length = 0; + + list_for_each_entry(t, &mesg->transfers, transfer_list) { + flags = 0; + + if (t->tx_buf) { + data = (char *) t->tx_buf; + write = 1; + } else if (t->rx_buf) { + data = (char *) t->rx_buf; + write = 0; + } else if (t->rx_buf && t->tx_buf) { + dev_err(master->dev, "Cannot send and receive simultaneously\n"); + return -EIO; + } else if (!t->rx_buf && !t->tx_buf) { + dev_err(master->dev, "No Data\n"); + return -EIO; + } + + if (&t->transfer_list == mesg->transfers.next) + flags |= SPI_XFER_BEGIN; + + if (&t->transfer_list == mesg->transfers.prev) + flags |= SPI_XFER_END; + + if (t->len == 0) { + if (flags == SPI_XFER_END) { + t->len = 1; + t->rx_buf = (void *) &dummy; + } else { + return 0; + } + } + + writel(SSP_CTRL1_DMA_ENABLE, mxs->regs + HW_SSP_CTRL1 + BIT_CLR); + ret = mxs_spi_xfer_pio(spi, data, t->len, write, flags); + if (ret < 0) + return ret; + mesg->actual_length += t->len; + } + + return 0; +} + +static int mxs_spi_probe(struct device_d *dev) +{ + struct spi_master *master; + struct mxs_spi *mxs; + + mxs = xzalloc(sizeof(*mxs)); + + master = &mxs->master; + master->dev = dev; + + master->bus_num = dev->id; + master->setup = mxs_spi_setup; + master->transfer = mxs_spi_transfer; + master->num_chipselect = 3; + mxs->mode = SPI_CPOL | SPI_CPHA; + + mxs->regs = dev_request_mem_region(dev, 0); + + spi_register_master(master); + + return 0; +} + +static struct driver_d mxs_spi_driver = { + .name = "mxs_spi", + .probe = mxs_spi_probe, +}; + +static int __init mxs_spi_init(void) +{ + return platform_driver_register(&mxs_spi_driver); +} + +device_initcall(mxs_spi_init); + +MODULE_AUTHOR("Denx Software Engeneering and Michael Grzeschik"); +MODULE_DESCRIPTION("MXS SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/include/envfs.h b/include/envfs.h index 2db55ed..e9372b3 100644 --- a/include/envfs.h +++ b/include/envfs.h @@ -96,4 +96,6 @@ /* defaults to /dev/env0 */ extern char *default_environment_path; +int envfs_register_partition(const char *devname, unsigned int partnr); + #endif /* _ENVFS_H */