Merge branch 'davinci-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci
* 'davinci-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci: (50 commits) davinci: fix remaining board support after io_pgoffst removal davinci: mityomapl138: make file local data static arm/davinci: remove duplicated include davinci: Initial support for Omapl138-Hawkboard davinci: MityDSP-L138/MityARM-1808 read MAC address from I2C Prom davinci: add tnetv107x touchscreen platform device input: add driver for tnetv107x touchscreen controller davinci: add keypad config for tnetv107x evm board davinci: add tnetv107x keypad platform device input: add driver for tnetv107x on-chip keypad controller net: davinci_emac: cleanup unused cpdma code net: davinci_emac: switch to new cpdma layer net: davinci_emac: separate out cpdma code net: davinci_emac: cleanup unused mdio emac code omap: cleanup unused davinci mdio arch code davinci: cleanup mdio arch code and switch to phy_id net: davinci_emac: switch to new mdio omap: add mdio platform devices davinci: add mdio platform devices net: davinci_emac: separate out davinci mdio ... Fix up trivial conflict in drivers/input/keyboard/Kconfig (two entries added next to each other - one from the davinci merge, one from the input merge)
This commit is contained in:
Коммит
72e58063d6
|
@ -5388,8 +5388,8 @@ F: drivers/*/*s3c2410*
|
|||
F: drivers/*/*/*s3c2410*
|
||||
|
||||
TI DAVINCI MACHINE SUPPORT
|
||||
P: Kevin Hilman
|
||||
M: davinci-linux-open-source@linux.davincidsp.com
|
||||
M: Kevin Hilman <khilman@deeprootsystems.com>
|
||||
L: davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
|
||||
Q: http://patchwork.kernel.org/project/linux-davinci/list/
|
||||
S: Supported
|
||||
F: arch/arm/mach-davinci
|
||||
|
|
|
@ -17,6 +17,8 @@ CONFIG_MODVERSIONS=y
|
|||
CONFIG_ARCH_DAVINCI=y
|
||||
CONFIG_ARCH_DAVINCI_DA830=y
|
||||
CONFIG_ARCH_DAVINCI_DA850=y
|
||||
CONFIG_MACH_MITYOMAPL138=y
|
||||
CONFIG_MACH_OMAPL138_HAWKBOARD=y
|
||||
CONFIG_DAVINCI_RESET_CLOCKS=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
|
@ -79,6 +81,7 @@ CONFIG_I2C_DAVINCI=y
|
|||
# CONFIG_HWMON is not set
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_DUMMY=y
|
||||
CONFIG_REGULATOR_TPS6507X=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_DA8XX=y
|
||||
|
|
|
@ -20,23 +20,23 @@ config ARCH_DAVINCI_DM644x
|
|||
select ARCH_DAVINCI_DMx
|
||||
|
||||
config ARCH_DAVINCI_DM355
|
||||
bool "DaVinci 355 based system"
|
||||
bool "DaVinci 355 based system"
|
||||
select AINTC
|
||||
select ARCH_DAVINCI_DMx
|
||||
|
||||
config ARCH_DAVINCI_DM646x
|
||||
bool "DaVinci 646x based system"
|
||||
bool "DaVinci 646x based system"
|
||||
select AINTC
|
||||
select ARCH_DAVINCI_DMx
|
||||
|
||||
config ARCH_DAVINCI_DA830
|
||||
bool "DA830/OMAP-L137 based system"
|
||||
bool "DA830/OMAP-L137/AM17x based system"
|
||||
select CP_INTC
|
||||
select ARCH_DAVINCI_DA8XX
|
||||
select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
|
||||
|
||||
config ARCH_DAVINCI_DA850
|
||||
bool "DA850/OMAP-L138 based system"
|
||||
bool "DA850/OMAP-L138/AM18x based system"
|
||||
select CP_INTC
|
||||
select ARCH_DAVINCI_DA8XX
|
||||
select ARCH_HAS_CPUFREQ
|
||||
|
@ -115,21 +115,21 @@ config MACH_DAVINCI_DM365_EVM
|
|||
for development is a DM365 EVM
|
||||
|
||||
config MACH_DAVINCI_DA830_EVM
|
||||
bool "TI DA830/OMAP-L137 Reference Platform"
|
||||
bool "TI DA830/OMAP-L137/AM17x Reference Platform"
|
||||
default ARCH_DAVINCI_DA830
|
||||
depends on ARCH_DAVINCI_DA830
|
||||
select GPIO_PCF857X
|
||||
help
|
||||
Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
|
||||
Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module.
|
||||
|
||||
choice
|
||||
prompt "Select DA830/OMAP-L137 UI board peripheral"
|
||||
prompt "Select DA830/OMAP-L137/AM17x UI board peripheral"
|
||||
depends on MACH_DAVINCI_DA830_EVM
|
||||
help
|
||||
The presence of UI card on the DA830/OMAP-L137 EVM is detected
|
||||
automatically based on successful probe of the I2C based GPIO
|
||||
expander on that board. This option selected in this menu has
|
||||
an effect only in case of a successful UI card detection.
|
||||
The presence of UI card on the DA830/OMAP-L137/AM17x EVM is
|
||||
detected automatically based on successful probe of the I2C
|
||||
based GPIO expander on that board. This option selected in this
|
||||
menu has an effect only in case of a successful UI card detection.
|
||||
|
||||
config DA830_UI_LCD
|
||||
bool "LCD"
|
||||
|
@ -140,23 +140,23 @@ config DA830_UI_LCD
|
|||
config DA830_UI_NAND
|
||||
bool "NAND flash"
|
||||
help
|
||||
Say Y here to use the NAND flash. Do not forget to setup
|
||||
Say Y here to use the NAND flash. Do not forget to setup
|
||||
the switch correctly.
|
||||
endchoice
|
||||
|
||||
config MACH_DAVINCI_DA850_EVM
|
||||
bool "TI DA850/OMAP-L138 Reference Platform"
|
||||
bool "TI DA850/OMAP-L138/AM18x Reference Platform"
|
||||
default ARCH_DAVINCI_DA850
|
||||
depends on ARCH_DAVINCI_DA850
|
||||
select GPIO_PCA953X
|
||||
help
|
||||
Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
|
||||
Say Y here to select the TI DA850/OMAP-L138/AM18x Evaluation Module.
|
||||
|
||||
choice
|
||||
prompt "Select peripherals connected to expander on UI board"
|
||||
depends on MACH_DAVINCI_DA850_EVM
|
||||
help
|
||||
The presence of User Interface (UI) card on the DA850/OMAP-L138
|
||||
The presence of User Interface (UI) card on the DA850/OMAP-L138/AM18x
|
||||
EVM is detected automatically based on successful probe of the I2C
|
||||
based GPIO expander on that card. This option selected in this
|
||||
menu has an effect only in case of a successful UI card detection.
|
||||
|
@ -165,13 +165,13 @@ config DA850_UI_NONE
|
|||
bool "No peripheral is enabled"
|
||||
help
|
||||
Say Y if you do not want to enable any of the peripherals connected
|
||||
to TCA6416 expander on DA850/OMAP-L138 EVM UI card
|
||||
to TCA6416 expander on DA850/OMAP-L138/AM18x EVM UI card
|
||||
|
||||
config DA850_UI_RMII
|
||||
bool "RMII Ethernet PHY"
|
||||
help
|
||||
Say Y if you want to use the RMII PHY on the DA850/OMAP-L138 EVM.
|
||||
This PHY is found on the UI daughter card that is supplied with
|
||||
Say Y if you want to use the RMII PHY on the DA850/OMAP-L138/AM18x
|
||||
EVM. This PHY is found on the UI daughter card that is supplied with
|
||||
the EVM.
|
||||
NOTE: Please take care while choosing this option, MII PHY will
|
||||
not be functional if RMII mode is selected.
|
||||
|
@ -185,6 +185,22 @@ config MACH_TNETV107X
|
|||
help
|
||||
Say Y here to select the TI TNETV107X Evaluation Module.
|
||||
|
||||
config MACH_MITYOMAPL138
|
||||
bool "Critical Link MityDSP-L138/MityARM-1808 SoM"
|
||||
depends on ARCH_DAVINCI_DA850
|
||||
help
|
||||
Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
|
||||
System on Module. Information on this SoM may be found at
|
||||
http://www.mitydsp.com
|
||||
|
||||
config MACH_OMAPL138_HAWKBOARD
|
||||
bool "TI AM1808 / OMAPL-138 Hawkboard platform"
|
||||
depends on ARCH_DAVINCI_DA850
|
||||
help
|
||||
Say Y here to select the TI AM1808 / OMAPL-138 Hawkboard platform .
|
||||
Information of this board may be found at
|
||||
http://www.hawkboard.org/
|
||||
|
||||
config DAVINCI_MUX
|
||||
bool "DAVINCI multiplexing support"
|
||||
depends on ARCH_DAVINCI
|
||||
|
@ -195,20 +211,20 @@ config DAVINCI_MUX
|
|||
say Y.
|
||||
|
||||
config DAVINCI_MUX_DEBUG
|
||||
bool "Multiplexing debug output"
|
||||
depends on DAVINCI_MUX
|
||||
help
|
||||
Makes the multiplexing functions print out a lot of debug info.
|
||||
This is useful if you want to find out the correct values of the
|
||||
multiplexing registers.
|
||||
bool "Multiplexing debug output"
|
||||
depends on DAVINCI_MUX
|
||||
help
|
||||
Makes the multiplexing functions print out a lot of debug info.
|
||||
This is useful if you want to find out the correct values of the
|
||||
multiplexing registers.
|
||||
|
||||
config DAVINCI_MUX_WARNINGS
|
||||
bool "Warn about pins the bootloader didn't set up"
|
||||
depends on DAVINCI_MUX
|
||||
help
|
||||
Choose Y here to warn whenever driver initialization logic needs
|
||||
to change the pin multiplexing setup. When there are no warnings
|
||||
printed, it's safe to deselect DAVINCI_MUX for your product.
|
||||
bool "Warn about pins the bootloader didn't set up"
|
||||
depends on DAVINCI_MUX
|
||||
help
|
||||
Choose Y here to warn whenever driver initialization logic needs
|
||||
to change the pin multiplexing setup. When there are no warnings
|
||||
printed, it's safe to deselect DAVINCI_MUX for your product.
|
||||
|
||||
config DAVINCI_RESET_CLOCKS
|
||||
bool "Reset unused clocks during boot"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
# Common objects
|
||||
obj-y := time.o clock.o serial.o io.o psc.o \
|
||||
gpio.o dma.o usb.o common.o sram.o
|
||||
gpio.o dma.o usb.o common.o sram.o aemif.o
|
||||
|
||||
obj-$(CONFIG_DAVINCI_MUX) += mux.o
|
||||
|
||||
|
@ -33,6 +33,8 @@ obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
|
|||
obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
|
||||
obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
|
||||
obj-$(CONFIG_MACH_TNETV107X) += board-tnetv107x-evm.o
|
||||
obj-$(CONFIG_MACH_MITYOMAPL138) += board-mityomapl138.o
|
||||
obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o
|
||||
|
||||
# Power Management
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* AEMIF support for DaVinci SoCs
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Incorporated. http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <mach/aemif.h>
|
||||
|
||||
/* Timing value configuration */
|
||||
|
||||
#define TA(x) ((x) << 2)
|
||||
#define RHOLD(x) ((x) << 4)
|
||||
#define RSTROBE(x) ((x) << 7)
|
||||
#define RSETUP(x) ((x) << 13)
|
||||
#define WHOLD(x) ((x) << 17)
|
||||
#define WSTROBE(x) ((x) << 20)
|
||||
#define WSETUP(x) ((x) << 26)
|
||||
|
||||
#define TA_MAX 0x3
|
||||
#define RHOLD_MAX 0x7
|
||||
#define RSTROBE_MAX 0x3f
|
||||
#define RSETUP_MAX 0xf
|
||||
#define WHOLD_MAX 0x7
|
||||
#define WSTROBE_MAX 0x3f
|
||||
#define WSETUP_MAX 0xf
|
||||
|
||||
#define TIMING_MASK (TA(TA_MAX) | \
|
||||
RHOLD(RHOLD_MAX) | \
|
||||
RSTROBE(RSTROBE_MAX) | \
|
||||
RSETUP(RSETUP_MAX) | \
|
||||
WHOLD(WHOLD_MAX) | \
|
||||
WSTROBE(WSTROBE_MAX) | \
|
||||
WSETUP(WSETUP_MAX))
|
||||
|
||||
/*
|
||||
* aemif_calc_rate - calculate timing data.
|
||||
* @wanted: The cycle time needed in nanoseconds.
|
||||
* @clk: The input clock rate in kHz.
|
||||
* @max: The maximum divider value that can be programmed.
|
||||
*
|
||||
* On success, returns the calculated timing value minus 1 for easy
|
||||
* programming into AEMIF timing registers, else negative errno.
|
||||
*/
|
||||
static int aemif_calc_rate(int wanted, unsigned long clk, int max)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
|
||||
|
||||
pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
|
||||
|
||||
/* It is generally OK to have a more relaxed timing than requested... */
|
||||
if (result < 0)
|
||||
result = 0;
|
||||
|
||||
/* ... But configuring tighter timings is not an option. */
|
||||
else if (result > max)
|
||||
result = -EINVAL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
|
||||
* @t: timing values to be progammed
|
||||
* @base: The virtual base address of the AEMIF interface
|
||||
* @cs: chip-select to program the timing values for
|
||||
*
|
||||
* This function programs the given timing values (in real clock) into the
|
||||
* AEMIF registers taking the AEMIF clock into account.
|
||||
*
|
||||
* This function does not use any locking while programming the AEMIF
|
||||
* because it is expected that there is only one user of a given
|
||||
* chip-select.
|
||||
*
|
||||
* Returns 0 on success, else negative errno.
|
||||
*/
|
||||
int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
|
||||
void __iomem *base, unsigned cs)
|
||||
{
|
||||
unsigned set, val;
|
||||
unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
|
||||
unsigned offset = A1CR_OFFSET + cs * 4;
|
||||
struct clk *aemif_clk;
|
||||
unsigned long clkrate;
|
||||
|
||||
if (!t)
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
aemif_clk = clk_get(NULL, "aemif");
|
||||
if (IS_ERR(aemif_clk))
|
||||
return PTR_ERR(aemif_clk);
|
||||
|
||||
clkrate = clk_get_rate(aemif_clk);
|
||||
|
||||
clkrate /= 1000; /* turn clock into kHz for ease of use */
|
||||
|
||||
ta = aemif_calc_rate(t->ta, clkrate, TA_MAX);
|
||||
rhold = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
|
||||
rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
|
||||
rsetup = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
|
||||
whold = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
|
||||
wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
|
||||
wsetup = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
|
||||
|
||||
if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
|
||||
whold < 0 || wstrobe < 0 || wsetup < 0) {
|
||||
pr_err("%s: cannot get suitable timings\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
|
||||
WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
|
||||
|
||||
val = __raw_readl(base + offset);
|
||||
val &= ~TIMING_MASK;
|
||||
val |= set;
|
||||
__raw_writel(val, base + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(davinci_aemif_setup_timing);
|
|
@ -29,10 +29,9 @@
|
|||
#include <mach/nand.h>
|
||||
#include <mach/da8xx.h>
|
||||
#include <mach/usb.h>
|
||||
#include <mach/aemif.h>
|
||||
|
||||
#define DA830_EVM_PHY_MASK 0x0
|
||||
#define DA830_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
|
||||
|
||||
#define DA830_EVM_PHY_ID ""
|
||||
/*
|
||||
* USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
|
||||
*/
|
||||
|
@ -360,6 +359,16 @@ static struct nand_bbt_descr da830_evm_nand_bbt_mirror_descr = {
|
|||
.pattern = da830_evm_nand_mirror_pattern
|
||||
};
|
||||
|
||||
static struct davinci_aemif_timing da830_evm_nandflash_timing = {
|
||||
.wsetup = 24,
|
||||
.wstrobe = 21,
|
||||
.whold = 14,
|
||||
.rsetup = 19,
|
||||
.rstrobe = 50,
|
||||
.rhold = 0,
|
||||
.ta = 20,
|
||||
};
|
||||
|
||||
static struct davinci_nand_pdata da830_evm_nand_pdata = {
|
||||
.parts = da830_evm_nand_partitions,
|
||||
.nr_parts = ARRAY_SIZE(da830_evm_nand_partitions),
|
||||
|
@ -368,6 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = {
|
|||
.options = NAND_USE_FLASH_BBT,
|
||||
.bbt_td = &da830_evm_nand_bbt_main_descr,
|
||||
.bbt_md = &da830_evm_nand_bbt_mirror_descr,
|
||||
.timing = &da830_evm_nandflash_timing,
|
||||
};
|
||||
|
||||
static struct resource da830_evm_nand_resources[] = {
|
||||
|
@ -546,9 +556,8 @@ static __init void da830_evm_init(void)
|
|||
|
||||
da830_evm_usb_init();
|
||||
|
||||
soc_info->emac_pdata->phy_mask = DA830_EVM_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = DA830_EVM_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->rmii_en = 1;
|
||||
soc_info->emac_pdata->phy_id = DA830_EVM_PHY_ID;
|
||||
|
||||
ret = davinci_cfg_reg_list(da830_cpgmac_pins);
|
||||
if (ret)
|
||||
|
@ -586,6 +595,9 @@ static __init void da830_evm_init(void)
|
|||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init da830_evm_console_init(void)
|
||||
{
|
||||
if (!machine_is_davinci_da830_evm())
|
||||
return 0;
|
||||
|
||||
return add_preferred_console("ttyS", 2, "115200");
|
||||
}
|
||||
console_initcall(da830_evm_console_init);
|
||||
|
@ -596,7 +608,7 @@ static void __init da830_evm_map_io(void)
|
|||
da830_init();
|
||||
}
|
||||
|
||||
MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
|
||||
MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
|
||||
.boot_params = (DA8XX_DDR_BASE + 0x100),
|
||||
.map_io = da830_evm_map_io,
|
||||
.init_irq = cp_intc_init,
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/tps6507x.h>
|
||||
#include <linux/mfd/tps6507x.h>
|
||||
#include <linux/input/tps6507x-ts.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
@ -36,10 +35,9 @@
|
|||
#include <mach/da8xx.h>
|
||||
#include <mach/nand.h>
|
||||
#include <mach/mux.h>
|
||||
#include <mach/aemif.h>
|
||||
|
||||
#define DA850_EVM_PHY_MASK 0x1
|
||||
#define DA850_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
|
||||
|
||||
#define DA850_EVM_PHY_ID "0:00"
|
||||
#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
|
||||
#define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15)
|
||||
|
||||
|
@ -110,7 +108,7 @@ static struct platform_device da850_pm_device = {
|
|||
* to boot, using TI's tools to install the secondary boot loader
|
||||
* (UBL) and U-Boot.
|
||||
*/
|
||||
struct mtd_partition da850_evm_nandflash_partition[] = {
|
||||
static struct mtd_partition da850_evm_nandflash_partition[] = {
|
||||
{
|
||||
.name = "u-boot env",
|
||||
.offset = 0,
|
||||
|
@ -143,12 +141,23 @@ struct mtd_partition da850_evm_nandflash_partition[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct davinci_aemif_timing da850_evm_nandflash_timing = {
|
||||
.wsetup = 24,
|
||||
.wstrobe = 21,
|
||||
.whold = 14,
|
||||
.rsetup = 19,
|
||||
.rstrobe = 50,
|
||||
.rhold = 0,
|
||||
.ta = 20,
|
||||
};
|
||||
|
||||
static struct davinci_nand_pdata da850_evm_nandflash_data = {
|
||||
.parts = da850_evm_nandflash_partition,
|
||||
.nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition),
|
||||
.ecc_mode = NAND_ECC_HW,
|
||||
.ecc_bits = 4,
|
||||
.options = NAND_USE_FLASH_BBT,
|
||||
.timing = &da850_evm_nandflash_timing,
|
||||
};
|
||||
|
||||
static struct resource da850_evm_nandflash_resource[] = {
|
||||
|
@ -196,6 +205,30 @@ static void __init da850_evm_init_nor(void)
|
|||
iounmap(aemif_addr);
|
||||
}
|
||||
|
||||
static const short da850_evm_nand_pins[] = {
|
||||
DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
|
||||
DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
|
||||
DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
|
||||
DA850_NEMA_WE, DA850_NEMA_OE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const short da850_evm_nor_pins[] = {
|
||||
DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
|
||||
DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
|
||||
DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
|
||||
DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
|
||||
DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
|
||||
DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
|
||||
DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
|
||||
DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
|
||||
DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
|
||||
DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
|
||||
DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
|
||||
DA850_EMA_A_22, DA850_EMA_A_23,
|
||||
-1
|
||||
};
|
||||
|
||||
static u32 ui_card_detected;
|
||||
|
||||
#if defined(CONFIG_MMC_DAVINCI) || \
|
||||
|
@ -205,17 +238,17 @@ static u32 ui_card_detected;
|
|||
#define HAS_MMC 0
|
||||
#endif
|
||||
|
||||
static __init void da850_evm_setup_nor_nand(void)
|
||||
static inline void da850_evm_setup_nor_nand(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ui_card_detected & !HAS_MMC) {
|
||||
ret = davinci_cfg_reg_list(da850_nand_pins);
|
||||
ret = davinci_cfg_reg_list(da850_evm_nand_pins);
|
||||
if (ret)
|
||||
pr_warning("da850_evm_init: nand mux setup failed: "
|
||||
"%d\n", ret);
|
||||
|
||||
ret = davinci_cfg_reg_list(da850_nor_pins);
|
||||
ret = davinci_cfg_reg_list(da850_evm_nor_pins);
|
||||
if (ret)
|
||||
pr_warning("da850_evm_init: nor mux setup failed: %d\n",
|
||||
ret);
|
||||
|
@ -406,7 +439,7 @@ static int da850_lcd_hw_init(void)
|
|||
/* TPS65070 voltage regulator support */
|
||||
|
||||
/* 3.3V */
|
||||
struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
|
||||
static struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
|
||||
{
|
||||
.supply = "usb0_vdda33",
|
||||
},
|
||||
|
@ -416,7 +449,7 @@ struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
|
|||
};
|
||||
|
||||
/* 3.3V or 1.8V */
|
||||
struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
|
||||
static struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
|
||||
{
|
||||
.supply = "dvdd3318_a",
|
||||
},
|
||||
|
@ -429,14 +462,14 @@ struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
|
|||
};
|
||||
|
||||
/* 1.2V */
|
||||
struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
|
||||
static struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
|
||||
{
|
||||
.supply = "cvdd",
|
||||
},
|
||||
};
|
||||
|
||||
/* 1.8V LDO */
|
||||
struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
|
||||
static struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
|
||||
{
|
||||
.supply = "sata_vddr",
|
||||
},
|
||||
|
@ -452,7 +485,7 @@ struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
|
|||
};
|
||||
|
||||
/* 1.2V LDO */
|
||||
struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
|
||||
static struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
|
||||
{
|
||||
.supply = "sata_vdd",
|
||||
},
|
||||
|
@ -475,7 +508,7 @@ static struct tps6507x_reg_platform_data tps6507x_platform_data = {
|
|||
.defdcdc_default = true,
|
||||
};
|
||||
|
||||
struct regulator_init_data tps65070_regulator_data[] = {
|
||||
static struct regulator_init_data tps65070_regulator_data[] = {
|
||||
/* dcdc1 */
|
||||
{
|
||||
.constraints = {
|
||||
|
@ -576,6 +609,23 @@ static const short da850_evm_lcdc_pins[] = {
|
|||
-1
|
||||
};
|
||||
|
||||
static const short da850_evm_mii_pins[] = {
|
||||
DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
|
||||
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
|
||||
DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
|
||||
DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
-1
|
||||
};
|
||||
|
||||
static const short da850_evm_rmii_pins[] = {
|
||||
DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
|
||||
DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
|
||||
DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
-1
|
||||
};
|
||||
|
||||
static int __init da850_evm_config_emac(void)
|
||||
{
|
||||
void __iomem *cfg_chip3_base;
|
||||
|
@ -593,12 +643,12 @@ static int __init da850_evm_config_emac(void)
|
|||
|
||||
if (rmii_en) {
|
||||
val |= BIT(8);
|
||||
ret = davinci_cfg_reg_list(da850_rmii_pins);
|
||||
ret = davinci_cfg_reg_list(da850_evm_rmii_pins);
|
||||
pr_info("EMAC: RMII PHY configured, MII PHY will not be"
|
||||
" functional\n");
|
||||
} else {
|
||||
val &= ~BIT(8);
|
||||
ret = davinci_cfg_reg_list(da850_cpgmac_pins);
|
||||
ret = davinci_cfg_reg_list(da850_evm_mii_pins);
|
||||
pr_info("EMAC: MII PHY configured, RMII PHY will not be"
|
||||
" functional\n");
|
||||
}
|
||||
|
@ -625,8 +675,7 @@ static int __init da850_evm_config_emac(void)
|
|||
/* Enable/Disable MII MDIO clock */
|
||||
gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, rmii_en);
|
||||
|
||||
soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->phy_id = DA850_EVM_PHY_ID;
|
||||
|
||||
ret = da8xx_register_emac();
|
||||
if (ret)
|
||||
|
@ -787,7 +836,7 @@ static __init void da850_evm_init(void)
|
|||
if (ret)
|
||||
pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
|
||||
|
||||
ret = da850_register_cpufreq();
|
||||
ret = da850_register_cpufreq("pll0_sysclk3");
|
||||
if (ret)
|
||||
pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
|
||||
ret);
|
||||
|
@ -806,6 +855,9 @@ static __init void da850_evm_init(void)
|
|||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init da850_evm_console_init(void)
|
||||
{
|
||||
if (!machine_is_davinci_da850_evm())
|
||||
return 0;
|
||||
|
||||
return add_preferred_console("ttyS", 2, "115200");
|
||||
}
|
||||
console_initcall(da850_evm_console_init);
|
||||
|
@ -816,7 +868,7 @@ static void __init da850_evm_map_io(void)
|
|||
da850_init();
|
||||
}
|
||||
|
||||
MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
|
||||
MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
|
||||
.boot_params = (DA8XX_DDR_BASE + 0x100),
|
||||
.map_io = da850_evm_map_io,
|
||||
.init_irq = cp_intc_init,
|
||||
|
|
|
@ -54,9 +54,7 @@ static inline int have_tvp7002(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define DM365_EVM_PHY_MASK (0x2)
|
||||
#define DM365_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
|
||||
|
||||
#define DM365_EVM_PHY_ID "0:01"
|
||||
/*
|
||||
* A MAX-II CPLD is used for various board control functions.
|
||||
*/
|
||||
|
@ -175,7 +173,9 @@ static struct at24_platform_data eeprom_info = {
|
|||
.context = (void *)0x7f00,
|
||||
};
|
||||
|
||||
static struct snd_platform_data dm365_evm_snd_data;
|
||||
static struct snd_platform_data dm365_evm_snd_data = {
|
||||
.asp_chan_q = EVENTQ_3,
|
||||
};
|
||||
|
||||
static struct i2c_board_info i2c_info[] = {
|
||||
{
|
||||
|
@ -533,8 +533,7 @@ fail:
|
|||
|
||||
/* ... and ENET ... */
|
||||
dm365evm_emac_configure();
|
||||
soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->phy_id = DM365_EVM_PHY_ID;
|
||||
resets &= ~BIT(3);
|
||||
|
||||
/* ... and AIC33 */
|
||||
|
|
|
@ -37,10 +37,9 @@
|
|||
#include <mach/nand.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/usb.h>
|
||||
#include <mach/aemif.h>
|
||||
|
||||
#define DM644X_EVM_PHY_MASK (0x2)
|
||||
#define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
|
||||
|
||||
#define DM644X_EVM_PHY_ID "0:01"
|
||||
#define LXT971_PHY_ID (0x001378e2)
|
||||
#define LXT971_PHY_MASK (0xfffffff0)
|
||||
|
||||
|
@ -137,11 +136,22 @@ static struct mtd_partition davinci_evm_nandflash_partition[] = {
|
|||
*/
|
||||
};
|
||||
|
||||
static struct davinci_aemif_timing davinci_evm_nandflash_timing = {
|
||||
.wsetup = 20,
|
||||
.wstrobe = 40,
|
||||
.whold = 20,
|
||||
.rsetup = 10,
|
||||
.rstrobe = 40,
|
||||
.rhold = 10,
|
||||
.ta = 40,
|
||||
};
|
||||
|
||||
static struct davinci_nand_pdata davinci_evm_nandflash_data = {
|
||||
.parts = davinci_evm_nandflash_partition,
|
||||
.nr_parts = ARRAY_SIZE(davinci_evm_nandflash_partition),
|
||||
.ecc_mode = NAND_ECC_HW,
|
||||
.options = NAND_USE_FLASH_BBT,
|
||||
.timing = &davinci_evm_nandflash_timing,
|
||||
};
|
||||
|
||||
static struct resource davinci_evm_nandflash_resource[] = {
|
||||
|
@ -695,9 +705,7 @@ static __init void davinci_evm_init(void)
|
|||
davinci_serial_init(&uart_config);
|
||||
dm644x_init_asp(&dm644x_evm_snd_data);
|
||||
|
||||
soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
|
||||
|
||||
soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
|
||||
/* Register the fixup for PHY on DaVinci */
|
||||
phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
|
||||
davinci_phy_fixup);
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <mach/nand.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/cdce949.h>
|
||||
#include <mach/aemif.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
|
@ -71,6 +72,16 @@ static struct mtd_partition davinci_nand_partitions[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct davinci_aemif_timing dm6467tevm_nandflash_timing = {
|
||||
.wsetup = 29,
|
||||
.wstrobe = 24,
|
||||
.whold = 14,
|
||||
.rsetup = 19,
|
||||
.rstrobe = 33,
|
||||
.rhold = 0,
|
||||
.ta = 29,
|
||||
};
|
||||
|
||||
static struct davinci_nand_pdata davinci_nand_data = {
|
||||
.mask_cle = 0x80000,
|
||||
.mask_ale = 0x40000,
|
||||
|
@ -718,9 +729,7 @@ static struct davinci_uart_config uart_config __initdata = {
|
|||
.enabled_uarts = (1 << 0),
|
||||
};
|
||||
|
||||
#define DM646X_EVM_PHY_MASK (0x2)
|
||||
#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
|
||||
|
||||
#define DM646X_EVM_PHY_ID "0:01"
|
||||
/*
|
||||
* The following EDMA channels/slots are not being used by drivers (for
|
||||
* example: Timer, GPIO, UART events etc) on dm646x, hence they are being
|
||||
|
@ -763,6 +772,9 @@ static __init void evm_init(void)
|
|||
dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
|
||||
dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
|
||||
|
||||
if (machine_is_davinci_dm6467tevm())
|
||||
davinci_nand_data.timing = &dm6467tevm_nandflash_timing;
|
||||
|
||||
platform_device_register(&davinci_nand_device);
|
||||
|
||||
dm646x_init_edma(dm646x_edma_rsv);
|
||||
|
@ -770,8 +782,7 @@ static __init void evm_init(void)
|
|||
if (HAS_ATA)
|
||||
davinci_init_ide();
|
||||
|
||||
soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID;
|
||||
}
|
||||
|
||||
#define DM646X_EVM_REF_FREQ 27000000
|
||||
|
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Critical Link MityOMAP-L138 SoM
|
||||
*
|
||||
* Copyright (C) 2010 Critical Link LLC - http://www.criticallink.com
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of
|
||||
* any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <mach/common.h>
|
||||
#include <mach/cp_intc.h>
|
||||
#include <mach/da8xx.h>
|
||||
#include <mach/nand.h>
|
||||
#include <mach/mux.h>
|
||||
|
||||
#define MITYOMAPL138_PHY_ID "0:03"
|
||||
|
||||
#define FACTORY_CONFIG_MAGIC 0x012C0138
|
||||
#define FACTORY_CONFIG_VERSION 0x00010001
|
||||
|
||||
/* Data Held in On-Board I2C device */
|
||||
struct factory_config {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u8 mac[6];
|
||||
u32 fpga_type;
|
||||
u32 spare;
|
||||
u32 serialnumber;
|
||||
char partnum[32];
|
||||
};
|
||||
|
||||
static struct factory_config factory_config;
|
||||
|
||||
static void read_factory_config(struct memory_accessor *a, void *context)
|
||||
{
|
||||
int ret;
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
|
||||
ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
|
||||
if (ret != sizeof(struct factory_config)) {
|
||||
pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
|
||||
pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
|
||||
factory_config.magic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (factory_config.version != FACTORY_CONFIG_VERSION) {
|
||||
pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
|
||||
factory_config.version);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
|
||||
pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum);
|
||||
if (is_valid_ether_addr(factory_config.mac))
|
||||
memcpy(soc_info->emac_pdata->mac_addr,
|
||||
factory_config.mac, ETH_ALEN);
|
||||
else
|
||||
pr_warning("MityOMAPL138: Invalid MAC found "
|
||||
"in factory config block\n");
|
||||
}
|
||||
|
||||
static struct at24_platform_data mityomapl138_fd_chip = {
|
||||
.byte_len = 256,
|
||||
.page_size = 8,
|
||||
.flags = AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
|
||||
.setup = read_factory_config,
|
||||
.context = NULL,
|
||||
};
|
||||
|
||||
static struct davinci_i2c_platform_data mityomap_i2c_0_pdata = {
|
||||
.bus_freq = 100, /* kHz */
|
||||
.bus_delay = 0, /* usec */
|
||||
};
|
||||
|
||||
/* TPS65023 voltage regulator support */
|
||||
/* 1.2V Core */
|
||||
static struct regulator_consumer_supply tps65023_dcdc1_consumers[] = {
|
||||
{
|
||||
.supply = "cvdd",
|
||||
},
|
||||
};
|
||||
|
||||
/* 1.8V */
|
||||
static struct regulator_consumer_supply tps65023_dcdc2_consumers[] = {
|
||||
{
|
||||
.supply = "usb0_vdda18",
|
||||
},
|
||||
{
|
||||
.supply = "usb1_vdda18",
|
||||
},
|
||||
{
|
||||
.supply = "ddr_dvdd18",
|
||||
},
|
||||
{
|
||||
.supply = "sata_vddr",
|
||||
},
|
||||
};
|
||||
|
||||
/* 1.2V */
|
||||
static struct regulator_consumer_supply tps65023_dcdc3_consumers[] = {
|
||||
{
|
||||
.supply = "sata_vdd",
|
||||
},
|
||||
{
|
||||
.supply = "usb_cvdd",
|
||||
},
|
||||
{
|
||||
.supply = "pll0_vdda",
|
||||
},
|
||||
{
|
||||
.supply = "pll1_vdda",
|
||||
},
|
||||
};
|
||||
|
||||
/* 1.8V Aux LDO, not used */
|
||||
static struct regulator_consumer_supply tps65023_ldo1_consumers[] = {
|
||||
{
|
||||
.supply = "1.8v_aux",
|
||||
},
|
||||
};
|
||||
|
||||
/* FPGA VCC Aux (2.5 or 3.3) LDO */
|
||||
static struct regulator_consumer_supply tps65023_ldo2_consumers[] = {
|
||||
{
|
||||
.supply = "vccaux",
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_init_data tps65023_regulator_data[] = {
|
||||
/* dcdc1 */
|
||||
{
|
||||
.constraints = {
|
||||
.min_uV = 1150000,
|
||||
.max_uV = 1350000,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
|
||||
REGULATOR_CHANGE_STATUS,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1_consumers),
|
||||
.consumer_supplies = tps65023_dcdc1_consumers,
|
||||
},
|
||||
/* dcdc2 */
|
||||
{
|
||||
.constraints = {
|
||||
.min_uV = 1800000,
|
||||
.max_uV = 1800000,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc2_consumers),
|
||||
.consumer_supplies = tps65023_dcdc2_consumers,
|
||||
},
|
||||
/* dcdc3 */
|
||||
{
|
||||
.constraints = {
|
||||
.min_uV = 1200000,
|
||||
.max_uV = 1200000,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc3_consumers),
|
||||
.consumer_supplies = tps65023_dcdc3_consumers,
|
||||
},
|
||||
/* ldo1 */
|
||||
{
|
||||
.constraints = {
|
||||
.min_uV = 1800000,
|
||||
.max_uV = 1800000,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(tps65023_ldo1_consumers),
|
||||
.consumer_supplies = tps65023_ldo1_consumers,
|
||||
},
|
||||
/* ldo2 */
|
||||
{
|
||||
.constraints = {
|
||||
.min_uV = 2500000,
|
||||
.max_uV = 3300000,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
|
||||
REGULATOR_CHANGE_STATUS,
|
||||
.boot_on = 1,
|
||||
},
|
||||
.num_consumer_supplies = ARRAY_SIZE(tps65023_ldo2_consumers),
|
||||
.consumer_supplies = tps65023_ldo2_consumers,
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata mityomap_tps65023_info[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("tps65023", 0x48),
|
||||
.platform_data = &tps65023_regulator_data[0],
|
||||
},
|
||||
{
|
||||
I2C_BOARD_INFO("24c02", 0x50),
|
||||
.platform_data = &mityomapl138_fd_chip,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmic_tps65023_init(void)
|
||||
{
|
||||
return i2c_register_board_info(1, mityomap_tps65023_info,
|
||||
ARRAY_SIZE(mityomap_tps65023_info));
|
||||
}
|
||||
|
||||
/*
|
||||
* MityDSP-L138 includes a 256 MByte large-page NAND flash
|
||||
* (128K blocks).
|
||||
*/
|
||||
static struct mtd_partition mityomapl138_nandflash_partition[] = {
|
||||
{
|
||||
.name = "rootfs",
|
||||
.offset = 0,
|
||||
.size = SZ_128M,
|
||||
.mask_flags = 0, /* MTD_WRITEABLE, */
|
||||
},
|
||||
{
|
||||
.name = "homefs",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
.mask_flags = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct davinci_nand_pdata mityomapl138_nandflash_data = {
|
||||
.parts = mityomapl138_nandflash_partition,
|
||||
.nr_parts = ARRAY_SIZE(mityomapl138_nandflash_partition),
|
||||
.ecc_mode = NAND_ECC_HW,
|
||||
.options = NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16,
|
||||
.ecc_bits = 1, /* 4 bit mode is not supported with 16 bit NAND */
|
||||
};
|
||||
|
||||
static struct resource mityomapl138_nandflash_resource[] = {
|
||||
{
|
||||
.start = DA8XX_AEMIF_CS3_BASE,
|
||||
.end = DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = DA8XX_AEMIF_CTL_BASE,
|
||||
.end = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mityomapl138_nandflash_device = {
|
||||
.name = "davinci_nand",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &mityomapl138_nandflash_data,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(mityomapl138_nandflash_resource),
|
||||
.resource = mityomapl138_nandflash_resource,
|
||||
};
|
||||
|
||||
static struct platform_device *mityomapl138_devices[] __initdata = {
|
||||
&mityomapl138_nandflash_device,
|
||||
};
|
||||
|
||||
static void __init mityomapl138_setup_nand(void)
|
||||
{
|
||||
platform_add_devices(mityomapl138_devices,
|
||||
ARRAY_SIZE(mityomapl138_devices));
|
||||
}
|
||||
|
||||
static struct davinci_uart_config mityomapl138_uart_config __initdata = {
|
||||
.enabled_uarts = 0x7,
|
||||
};
|
||||
|
||||
static const short mityomap_mii_pins[] = {
|
||||
DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
|
||||
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
|
||||
DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
|
||||
DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
-1
|
||||
};
|
||||
|
||||
static const short mityomap_rmii_pins[] = {
|
||||
DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
|
||||
DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
|
||||
DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
-1
|
||||
};
|
||||
|
||||
static void __init mityomapl138_config_emac(void)
|
||||
{
|
||||
void __iomem *cfg_chip3_base;
|
||||
int ret;
|
||||
u32 val;
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
|
||||
soc_info->emac_pdata->rmii_en = 0; /* hardcoded for now */
|
||||
|
||||
cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
|
||||
val = __raw_readl(cfg_chip3_base);
|
||||
|
||||
if (soc_info->emac_pdata->rmii_en) {
|
||||
val |= BIT(8);
|
||||
ret = davinci_cfg_reg_list(mityomap_rmii_pins);
|
||||
pr_info("RMII PHY configured\n");
|
||||
} else {
|
||||
val &= ~BIT(8);
|
||||
ret = davinci_cfg_reg_list(mityomap_mii_pins);
|
||||
pr_info("MII PHY configured\n");
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
pr_warning("mii/rmii mux setup failed: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* configure the CFGCHIP3 register for RMII or MII */
|
||||
__raw_writel(val, cfg_chip3_base);
|
||||
|
||||
soc_info->emac_pdata->phy_id = MITYOMAPL138_PHY_ID;
|
||||
|
||||
ret = da8xx_register_emac();
|
||||
if (ret)
|
||||
pr_warning("emac registration failed: %d\n", ret);
|
||||
}
|
||||
|
||||
static struct davinci_pm_config da850_pm_pdata = {
|
||||
.sleepcount = 128,
|
||||
};
|
||||
|
||||
static struct platform_device da850_pm_device = {
|
||||
.name = "pm-davinci",
|
||||
.dev = {
|
||||
.platform_data = &da850_pm_pdata,
|
||||
},
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void __init mityomapl138_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* for now, no special EDMA channels are reserved */
|
||||
ret = da850_register_edma(NULL);
|
||||
if (ret)
|
||||
pr_warning("edma registration failed: %d\n", ret);
|
||||
|
||||
ret = da8xx_register_watchdog();
|
||||
if (ret)
|
||||
pr_warning("watchdog registration failed: %d\n", ret);
|
||||
|
||||
davinci_serial_init(&mityomapl138_uart_config);
|
||||
|
||||
ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata);
|
||||
if (ret)
|
||||
pr_warning("i2c0 registration failed: %d\n", ret);
|
||||
|
||||
ret = pmic_tps65023_init();
|
||||
if (ret)
|
||||
pr_warning("TPS65023 PMIC init failed: %d\n", ret);
|
||||
|
||||
mityomapl138_setup_nand();
|
||||
|
||||
mityomapl138_config_emac();
|
||||
|
||||
ret = da8xx_register_rtc();
|
||||
if (ret)
|
||||
pr_warning("rtc setup failed: %d\n", ret);
|
||||
|
||||
ret = da850_register_cpufreq("pll0_sysclk3");
|
||||
if (ret)
|
||||
pr_warning("cpufreq registration failed: %d\n", ret);
|
||||
|
||||
ret = da8xx_register_cpuidle();
|
||||
if (ret)
|
||||
pr_warning("cpuidle registration failed: %d\n", ret);
|
||||
|
||||
ret = da850_register_pm(&da850_pm_device);
|
||||
if (ret)
|
||||
pr_warning("da850_evm_init: suspend registration failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init mityomapl138_console_init(void)
|
||||
{
|
||||
if (!machine_is_mityomapl138())
|
||||
return 0;
|
||||
|
||||
return add_preferred_console("ttyS", 1, "115200");
|
||||
}
|
||||
console_initcall(mityomapl138_console_init);
|
||||
#endif
|
||||
|
||||
static void __init mityomapl138_map_io(void)
|
||||
{
|
||||
da850_init();
|
||||
}
|
||||
|
||||
MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
|
||||
.boot_params = (DA8XX_DDR_BASE + 0x100),
|
||||
.map_io = mityomapl138_map_io,
|
||||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = mityomapl138_init,
|
||||
MACHINE_END
|
|
@ -39,9 +39,7 @@
|
|||
#include <mach/mmc.h>
|
||||
#include <mach/usb.h>
|
||||
|
||||
#define NEUROS_OSD2_PHY_MASK 0x2
|
||||
#define NEUROS_OSD2_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
|
||||
|
||||
#define NEUROS_OSD2_PHY_ID "0:01"
|
||||
#define LXT971_PHY_ID 0x001378e2
|
||||
#define LXT971_PHY_MASK 0xfffffff0
|
||||
|
||||
|
@ -252,8 +250,7 @@ static __init void davinci_ntosd2_init(void)
|
|||
davinci_serial_init(&uart_config);
|
||||
dm644x_init_asp(&dm644x_ntosd2_snd_data);
|
||||
|
||||
soc_info->emac_pdata->phy_mask = NEUROS_OSD2_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = NEUROS_OSD2_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->phy_id = NEUROS_OSD2_PHY_ID;
|
||||
|
||||
davinci_setup_usb(1000, 8);
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Hawkboard.org based on TI's OMAP-L138 Platform
|
||||
*
|
||||
* Initial code: Syed Mohammed Khasim
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of
|
||||
* any kind, whether express or implied.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include <mach/cp_intc.h>
|
||||
#include <mach/da8xx.h>
|
||||
|
||||
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
|
||||
.enabled_uarts = 0x7,
|
||||
};
|
||||
|
||||
static __init void omapl138_hawk_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
davinci_serial_init(&omapl138_hawk_uart_config);
|
||||
|
||||
ret = da8xx_register_watchdog();
|
||||
if (ret)
|
||||
pr_warning("omapl138_hawk_init: "
|
||||
"watchdog registration failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init omapl138_hawk_console_init(void)
|
||||
{
|
||||
if (!machine_is_omapl138_hawkboard())
|
||||
return 0;
|
||||
|
||||
return add_preferred_console("ttyS", 2, "115200");
|
||||
}
|
||||
console_initcall(omapl138_hawk_console_init);
|
||||
#endif
|
||||
|
||||
static void __init omapl138_hawk_map_io(void)
|
||||
{
|
||||
da850_init();
|
||||
}
|
||||
|
||||
MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
|
||||
.boot_params = (DA8XX_DDR_BASE + 0x100),
|
||||
.map_io = omapl138_hawk_map_io,
|
||||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = omapl138_hawk_init,
|
||||
MACHINE_END
|
|
@ -42,9 +42,7 @@
|
|||
#include <mach/mux.h>
|
||||
#include <mach/usb.h>
|
||||
|
||||
#define SFFSDR_PHY_MASK (0x2)
|
||||
#define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
|
||||
|
||||
#define SFFSDR_PHY_ID "0:01"
|
||||
static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
|
||||
/* U-Boot Environment: Block 0
|
||||
* UBL: Block 1
|
||||
|
@ -143,8 +141,7 @@ static __init void davinci_sffsdr_init(void)
|
|||
ARRAY_SIZE(davinci_sffsdr_devices));
|
||||
sffsdr_init_i2c();
|
||||
davinci_serial_init(&uart_config);
|
||||
soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
|
||||
soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
|
||||
soc_info->emac_pdata->phy_id = SFFSDR_PHY_ID;
|
||||
davinci_setup_usb(0, 0); /* We support only peripheral mode. */
|
||||
|
||||
/* mux VLYNQ pins */
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <linux/ratelimit.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
@ -141,10 +144,63 @@ static struct davinci_uart_config serial_config __initconst = {
|
|||
.enabled_uarts = BIT(1),
|
||||
};
|
||||
|
||||
static const uint32_t keymap[] = {
|
||||
KEY(0, 0, KEY_NUMERIC_1),
|
||||
KEY(0, 1, KEY_NUMERIC_2),
|
||||
KEY(0, 2, KEY_NUMERIC_3),
|
||||
KEY(0, 3, KEY_FN_F1),
|
||||
KEY(0, 4, KEY_MENU),
|
||||
|
||||
KEY(1, 0, KEY_NUMERIC_4),
|
||||
KEY(1, 1, KEY_NUMERIC_5),
|
||||
KEY(1, 2, KEY_NUMERIC_6),
|
||||
KEY(1, 3, KEY_UP),
|
||||
KEY(1, 4, KEY_FN_F2),
|
||||
|
||||
KEY(2, 0, KEY_NUMERIC_7),
|
||||
KEY(2, 1, KEY_NUMERIC_8),
|
||||
KEY(2, 2, KEY_NUMERIC_9),
|
||||
KEY(2, 3, KEY_LEFT),
|
||||
KEY(2, 4, KEY_ENTER),
|
||||
|
||||
KEY(3, 0, KEY_NUMERIC_STAR),
|
||||
KEY(3, 1, KEY_NUMERIC_0),
|
||||
KEY(3, 2, KEY_NUMERIC_POUND),
|
||||
KEY(3, 3, KEY_DOWN),
|
||||
KEY(3, 4, KEY_RIGHT),
|
||||
|
||||
KEY(4, 0, KEY_FN_F3),
|
||||
KEY(4, 1, KEY_FN_F4),
|
||||
KEY(4, 2, KEY_MUTE),
|
||||
KEY(4, 3, KEY_HOME),
|
||||
KEY(4, 4, KEY_BACK),
|
||||
|
||||
KEY(5, 0, KEY_VOLUMEDOWN),
|
||||
KEY(5, 1, KEY_VOLUMEUP),
|
||||
KEY(5, 2, KEY_F1),
|
||||
KEY(5, 3, KEY_F2),
|
||||
KEY(5, 4, KEY_F3),
|
||||
};
|
||||
|
||||
static const struct matrix_keymap_data keymap_data = {
|
||||
.keymap = keymap,
|
||||
.keymap_size = ARRAY_SIZE(keymap),
|
||||
};
|
||||
|
||||
static struct matrix_keypad_platform_data keypad_config = {
|
||||
.keymap_data = &keymap_data,
|
||||
.num_row_gpios = 6,
|
||||
.num_col_gpios = 5,
|
||||
.debounce_ms = 0, /* minimum */
|
||||
.active_low = 0, /* pull up realization */
|
||||
.no_autorepeat = 0,
|
||||
};
|
||||
|
||||
static struct tnetv107x_device_info evm_device_info __initconst = {
|
||||
.serial_config = &serial_config,
|
||||
.mmc_config[1] = &mmc_config, /* controller 1 */
|
||||
.nand_config[0] = &nand_config, /* chip select 0 */
|
||||
.keypad_config = &keypad_config,
|
||||
};
|
||||
|
||||
static __init void tnetv107x_evm_board_init(void)
|
||||
|
|
|
@ -236,7 +236,7 @@ static int __init clk_disable_unused(void)
|
|||
if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
|
||||
continue;
|
||||
|
||||
pr_info("Clocks: disable unused %s\n", ck->name);
|
||||
pr_debug("Clocks: disable unused %s\n", ck->name);
|
||||
|
||||
davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc,
|
||||
(ck->flags & PSC_SWRSTDISABLE) ?
|
||||
|
@ -287,6 +287,79 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
|
|||
return rate;
|
||||
}
|
||||
|
||||
int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned v;
|
||||
struct pll_data *pll;
|
||||
unsigned long input;
|
||||
unsigned ratio = 0;
|
||||
|
||||
/* If this is the PLL base clock, wrong function to call */
|
||||
if (clk->pll_data)
|
||||
return -EINVAL;
|
||||
|
||||
/* There must be a parent... */
|
||||
if (WARN_ON(!clk->parent))
|
||||
return -EINVAL;
|
||||
|
||||
/* ... the parent must be a PLL... */
|
||||
if (WARN_ON(!clk->parent->pll_data))
|
||||
return -EINVAL;
|
||||
|
||||
/* ... and this clock must have a divider. */
|
||||
if (WARN_ON(!clk->div_reg))
|
||||
return -EINVAL;
|
||||
|
||||
pll = clk->parent->pll_data;
|
||||
|
||||
input = clk->parent->rate;
|
||||
|
||||
/* If pre-PLL, source clock is before the multiplier and divider(s) */
|
||||
if (clk->flags & PRE_PLL)
|
||||
input = pll->input_rate;
|
||||
|
||||
if (input > rate) {
|
||||
/*
|
||||
* Can afford to provide an output little higher than requested
|
||||
* only if maximum rate supported by hardware on this sysclk
|
||||
* is known.
|
||||
*/
|
||||
if (clk->maxrate) {
|
||||
ratio = DIV_ROUND_CLOSEST(input, rate);
|
||||
if (input / ratio > clk->maxrate)
|
||||
ratio = 0;
|
||||
}
|
||||
|
||||
if (ratio == 0)
|
||||
ratio = DIV_ROUND_UP(input, rate);
|
||||
|
||||
ratio--;
|
||||
}
|
||||
|
||||
if (ratio > PLLDIV_RATIO_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
v = __raw_readl(pll->base + PLLSTAT);
|
||||
} while (v & PLLSTAT_GOSTAT);
|
||||
|
||||
v = __raw_readl(pll->base + clk->div_reg);
|
||||
v &= ~PLLDIV_RATIO_MASK;
|
||||
v |= ratio | PLLDIV_EN;
|
||||
__raw_writel(v, pll->base + clk->div_reg);
|
||||
|
||||
v = __raw_readl(pll->base + PLLCMD);
|
||||
v |= PLLCMD_GOSET;
|
||||
__raw_writel(v, pll->base + PLLCMD);
|
||||
|
||||
do {
|
||||
v = __raw_readl(pll->base + PLLSTAT);
|
||||
} while (v & PLLSTAT_GOSTAT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(davinci_set_sysclk_rate);
|
||||
|
||||
static unsigned long clk_leafclk_recalc(struct clk *clk)
|
||||
{
|
||||
if (WARN_ON(!clk->parent))
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
#include <linux/list.h>
|
||||
#include <asm/clkdev.h>
|
||||
|
||||
#define PLLSTAT_GOSTAT BIT(0)
|
||||
#define PLLCMD_GOSET BIT(0)
|
||||
|
||||
struct pll_data {
|
||||
u32 phys_base;
|
||||
void __iomem *base;
|
||||
|
@ -86,6 +89,7 @@ struct clk {
|
|||
struct module *owner;
|
||||
const char *name;
|
||||
unsigned long rate;
|
||||
unsigned long maxrate; /* H/W supported max rate */
|
||||
u8 usecount;
|
||||
u8 lpsc;
|
||||
u8 gpsc;
|
||||
|
@ -118,6 +122,7 @@ struct clk {
|
|||
int davinci_clk_init(struct clk_lookup *clocks);
|
||||
int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
|
||||
unsigned int mult, unsigned int postdiv);
|
||||
int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
|
||||
|
||||
extern struct platform_device davinci_wdt_device;
|
||||
extern void davinci_watchdog_reset(struct platform_device *);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
struct davinci_cpufreq {
|
||||
struct device *dev;
|
||||
struct clk *armclk;
|
||||
struct clk *asyncclk;
|
||||
unsigned long asyncrate;
|
||||
};
|
||||
static struct davinci_cpufreq cpufreq;
|
||||
|
||||
|
@ -104,15 +106,27 @@ static int davinci_target(struct cpufreq_policy *policy,
|
|||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* if moving to higher frequency, up the voltage beforehand */
|
||||
if (pdata->set_voltage && freqs.new > freqs.old)
|
||||
pdata->set_voltage(idx);
|
||||
if (pdata->set_voltage && freqs.new > freqs.old) {
|
||||
ret = pdata->set_voltage(idx);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(armclk, idx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (cpufreq.asyncclk) {
|
||||
ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if moving to lower freq, lower the voltage after lowering freq */
|
||||
if (pdata->set_voltage && freqs.new < freqs.old)
|
||||
pdata->set_voltage(idx);
|
||||
|
||||
out:
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
|
@ -185,6 +199,7 @@ static struct cpufreq_driver davinci_driver = {
|
|||
static int __init davinci_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
|
||||
struct clk *asyncclk;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
@ -199,6 +214,12 @@ static int __init davinci_cpufreq_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(cpufreq.armclk);
|
||||
}
|
||||
|
||||
asyncclk = clk_get(cpufreq.dev, "async");
|
||||
if (!IS_ERR(asyncclk)) {
|
||||
cpufreq.asyncclk = asyncclk;
|
||||
cpufreq.asyncrate = clk_get_rate(asyncclk);
|
||||
}
|
||||
|
||||
return cpufreq_register_driver(&davinci_driver);
|
||||
}
|
||||
|
||||
|
@ -206,6 +227,9 @@ static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
|
|||
{
|
||||
clk_put(cpufreq.armclk);
|
||||
|
||||
if (cpufreq.asyncclk)
|
||||
clk_put(cpufreq.asyncclk);
|
||||
|
||||
return cpufreq_unregister_driver(&davinci_driver);
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,8 @@ static struct clk pll0_sysclk3 = {
|
|||
.parent = &pll0_clk,
|
||||
.flags = CLK_PLL,
|
||||
.div_reg = PLLDIV3,
|
||||
.set_rate = davinci_set_sysclk_rate,
|
||||
.maxrate = 100000000,
|
||||
};
|
||||
|
||||
static struct clk pll0_sysclk4 = {
|
||||
|
@ -323,12 +325,19 @@ static struct clk lcdc_clk = {
|
|||
.gpsc = 1,
|
||||
};
|
||||
|
||||
static struct clk mmcsd_clk = {
|
||||
.name = "mmcsd",
|
||||
static struct clk mmcsd0_clk = {
|
||||
.name = "mmcsd0",
|
||||
.parent = &pll0_sysclk2,
|
||||
.lpsc = DA8XX_LPSC0_MMC_SD,
|
||||
};
|
||||
|
||||
static struct clk mmcsd1_clk = {
|
||||
.name = "mmcsd1",
|
||||
.parent = &pll0_sysclk2,
|
||||
.lpsc = DA850_LPSC1_MMC_SD1,
|
||||
.gpsc = 1,
|
||||
};
|
||||
|
||||
static struct clk aemif_clk = {
|
||||
.name = "aemif",
|
||||
.parent = &pll0_sysclk3,
|
||||
|
@ -375,7 +384,8 @@ static struct clk_lookup da850_clks[] = {
|
|||
CLK("davinci_emac.1", NULL, &emac_clk),
|
||||
CLK("davinci-mcasp.0", NULL, &mcasp_clk),
|
||||
CLK("da8xx_lcdc.0", NULL, &lcdc_clk),
|
||||
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
|
||||
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
|
||||
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
|
||||
CLK(NULL, "aemif", &aemif_clk),
|
||||
CLK(NULL, NULL, NULL),
|
||||
};
|
||||
|
@ -572,15 +582,9 @@ const short da850_cpgmac_pins[] __initdata = {
|
|||
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
|
||||
DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
|
||||
DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
-1
|
||||
};
|
||||
|
||||
const short da850_rmii_pins[] __initdata = {
|
||||
DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
|
||||
DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
|
||||
DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
|
||||
DA850_MDIO_D,
|
||||
DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
|
||||
DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER,
|
||||
DA850_RMII_MHZ_50_CLK,
|
||||
-1
|
||||
};
|
||||
|
||||
|
@ -607,27 +611,19 @@ const short da850_mmcsd0_pins[] __initdata = {
|
|||
-1
|
||||
};
|
||||
|
||||
const short da850_nand_pins[] __initdata = {
|
||||
DA850_EMA_D_7, DA850_EMA_D_6, DA850_EMA_D_5, DA850_EMA_D_4,
|
||||
DA850_EMA_D_3, DA850_EMA_D_2, DA850_EMA_D_1, DA850_EMA_D_0,
|
||||
DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
|
||||
DA850_NEMA_WE, DA850_NEMA_OE,
|
||||
-1
|
||||
};
|
||||
|
||||
const short da850_nor_pins[] __initdata = {
|
||||
const short da850_emif25_pins[] __initdata = {
|
||||
DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
|
||||
DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
|
||||
DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
|
||||
DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
|
||||
DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
|
||||
DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
|
||||
DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
|
||||
DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
|
||||
DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
|
||||
DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
|
||||
DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
|
||||
DA850_EMA_A_22, DA850_EMA_A_23,
|
||||
DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE,
|
||||
DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
|
||||
DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
|
||||
DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
|
||||
DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
|
||||
DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3,
|
||||
DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7,
|
||||
DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11,
|
||||
DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15,
|
||||
DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19,
|
||||
DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23,
|
||||
-1
|
||||
};
|
||||
|
||||
|
@ -851,7 +847,7 @@ static const struct da850_opp da850_opp_300 = {
|
|||
.prediv = 1,
|
||||
.mult = 25,
|
||||
.postdiv = 2,
|
||||
.cvdd_min = 1140000,
|
||||
.cvdd_min = 1200000,
|
||||
.cvdd_max = 1320000,
|
||||
};
|
||||
|
||||
|
@ -860,7 +856,7 @@ static const struct da850_opp da850_opp_200 = {
|
|||
.prediv = 1,
|
||||
.mult = 25,
|
||||
.postdiv = 3,
|
||||
.cvdd_min = 1050000,
|
||||
.cvdd_min = 1100000,
|
||||
.cvdd_max = 1160000,
|
||||
};
|
||||
|
||||
|
@ -869,7 +865,7 @@ static const struct da850_opp da850_opp_96 = {
|
|||
.prediv = 1,
|
||||
.mult = 20,
|
||||
.postdiv = 5,
|
||||
.cvdd_min = 950000,
|
||||
.cvdd_min = 1000000,
|
||||
.cvdd_max = 1050000,
|
||||
};
|
||||
|
||||
|
@ -929,10 +925,16 @@ static struct platform_device da850_cpufreq_device = {
|
|||
.dev = {
|
||||
.platform_data = &cpufreq_info,
|
||||
},
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
int __init da850_register_cpufreq(void)
|
||||
int __init da850_register_cpufreq(char *async_clk)
|
||||
{
|
||||
/* cpufreq driver can help keep an "async" clock constant */
|
||||
if (async_clk)
|
||||
clk_add_alias("async", da850_cpufreq_device.name,
|
||||
async_clk, NULL);
|
||||
|
||||
return platform_device_register(&da850_cpufreq_device);
|
||||
}
|
||||
|
||||
|
@ -983,7 +985,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
int __init da850_register_cpufreq(void)
|
||||
int __init da850_register_cpufreq(char *async_clk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "clock.h"
|
||||
|
||||
#define DA8XX_TPCC_BASE 0x01c00000
|
||||
#define DA850_MMCSD1_BASE 0x01e1b000
|
||||
#define DA850_TPCC1_BASE 0x01e30000
|
||||
#define DA8XX_TPTC0_BASE 0x01c08000
|
||||
#define DA8XX_TPTC1_BASE 0x01c08400
|
||||
|
@ -41,7 +42,6 @@
|
|||
#define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000
|
||||
#define DA8XX_EMAC_MOD_REG_OFFSET 0x2000
|
||||
#define DA8XX_EMAC_RAM_OFFSET 0x0000
|
||||
#define DA8XX_MDIO_REG_OFFSET 0x4000
|
||||
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
|
||||
|
||||
void __iomem *da8xx_syscfg0_base;
|
||||
|
@ -351,7 +351,7 @@ int __init da8xx_register_watchdog(void)
|
|||
static struct resource da8xx_emac_resources[] = {
|
||||
{
|
||||
.start = DA8XX_EMAC_CPPI_PORT_BASE,
|
||||
.end = DA8XX_EMAC_CPPI_PORT_BASE + 0x5000 - 1,
|
||||
.end = DA8XX_EMAC_CPPI_PORT_BASE + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
|
@ -380,7 +380,6 @@ struct emac_platform_data da8xx_emac_pdata = {
|
|||
.ctrl_reg_offset = DA8XX_EMAC_CTRL_REG_OFFSET,
|
||||
.ctrl_mod_reg_offset = DA8XX_EMAC_MOD_REG_OFFSET,
|
||||
.ctrl_ram_offset = DA8XX_EMAC_RAM_OFFSET,
|
||||
.mdio_reg_offset = DA8XX_MDIO_REG_OFFSET,
|
||||
.ctrl_ram_size = DA8XX_EMAC_CTRL_RAM_SIZE,
|
||||
.version = EMAC_VERSION_2,
|
||||
};
|
||||
|
@ -395,9 +394,34 @@ static struct platform_device da8xx_emac_device = {
|
|||
.resource = da8xx_emac_resources,
|
||||
};
|
||||
|
||||
static struct resource da8xx_mdio_resources[] = {
|
||||
{
|
||||
.start = DA8XX_EMAC_MDIO_BASE,
|
||||
.end = DA8XX_EMAC_MDIO_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device da8xx_mdio_device = {
|
||||
.name = "davinci_mdio",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(da8xx_mdio_resources),
|
||||
.resource = da8xx_mdio_resources,
|
||||
};
|
||||
|
||||
int __init da8xx_register_emac(void)
|
||||
{
|
||||
return platform_device_register(&da8xx_emac_device);
|
||||
int ret;
|
||||
|
||||
ret = platform_device_register(&da8xx_mdio_device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = platform_device_register(&da8xx_emac_device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = clk_add_alias(NULL, dev_name(&da8xx_mdio_device.dev),
|
||||
NULL, &da8xx_emac_device.dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct resource da830_mcasp1_resources[] = {
|
||||
|
@ -566,6 +590,44 @@ int __init da8xx_register_mmcsd0(struct davinci_mmc_config *config)
|
|||
return platform_device_register(&da8xx_mmcsd0_device);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_DAVINCI_DA850
|
||||
static struct resource da850_mmcsd1_resources[] = {
|
||||
{ /* registers */
|
||||
.start = DA850_MMCSD1_BASE,
|
||||
.end = DA850_MMCSD1_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{ /* interrupt */
|
||||
.start = IRQ_DA850_MMCSDINT0_1,
|
||||
.end = IRQ_DA850_MMCSDINT0_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{ /* DMA RX */
|
||||
.start = EDMA_CTLR_CHAN(1, 28),
|
||||
.end = EDMA_CTLR_CHAN(1, 28),
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
{ /* DMA TX */
|
||||
.start = EDMA_CTLR_CHAN(1, 29),
|
||||
.end = EDMA_CTLR_CHAN(1, 29),
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device da850_mmcsd1_device = {
|
||||
.name = "davinci_mmc",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(da850_mmcsd1_resources),
|
||||
.resource = da850_mmcsd1_resources,
|
||||
};
|
||||
|
||||
int __init da850_register_mmcsd1(struct davinci_mmc_config *config)
|
||||
{
|
||||
da850_mmcsd1_device.dev.platform_data = config;
|
||||
return platform_device_register(&da850_mmcsd1_device);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct resource da8xx_rtc_resources[] = {
|
||||
{
|
||||
.start = DA8XX_RTC_BASE,
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
#define TNETV107X_TPTC0_BASE 0x01c10000
|
||||
#define TNETV107X_TPTC1_BASE 0x01c10400
|
||||
#define TNETV107X_WDOG_BASE 0x08086700
|
||||
#define TNETV107X_TSC_BASE 0x08088500
|
||||
#define TNETV107X_SDIO0_BASE 0x08088700
|
||||
#define TNETV107X_SDIO1_BASE 0x08088800
|
||||
#define TNETV107X_KEYPAD_BASE 0x08088a00
|
||||
#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000
|
||||
#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000
|
||||
#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000
|
||||
|
@ -298,12 +300,55 @@ static int __init nand_init(int chipsel, struct davinci_nand_pdata *data)
|
|||
return platform_device_register(pdev);
|
||||
}
|
||||
|
||||
static struct resource keypad_resources[] = {
|
||||
{
|
||||
.start = TNETV107X_KEYPAD_BASE,
|
||||
.end = TNETV107X_KEYPAD_BASE + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = IRQ_TNETV107X_KEYPAD,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "press",
|
||||
},
|
||||
{
|
||||
.start = IRQ_TNETV107X_KEYPAD_FREE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "release",
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device keypad_device = {
|
||||
.name = "tnetv107x-keypad",
|
||||
.num_resources = ARRAY_SIZE(keypad_resources),
|
||||
.resource = keypad_resources,
|
||||
};
|
||||
|
||||
static struct resource tsc_resources[] = {
|
||||
{
|
||||
.start = TNETV107X_TSC_BASE,
|
||||
.end = TNETV107X_TSC_BASE + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = IRQ_TNETV107X_TSC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device tsc_device = {
|
||||
.name = "tnetv107x-ts",
|
||||
.num_resources = ARRAY_SIZE(tsc_resources),
|
||||
.resource = tsc_resources,
|
||||
};
|
||||
|
||||
void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
platform_device_register(&edma_device);
|
||||
platform_device_register(&tnetv107x_wdt_device);
|
||||
platform_device_register(&tsc_device);
|
||||
|
||||
if (info->serial_config)
|
||||
davinci_serial_init(info->serial_config);
|
||||
|
@ -317,4 +362,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
|
|||
for (i = 0; i < 4; i++)
|
||||
if (info->nand_config[i])
|
||||
nand_init(i, info->nand_config[i]);
|
||||
|
||||
if (info->keypad_config) {
|
||||
keypad_device.dev.platform_data = info->keypad_config;
|
||||
platform_device_register(&keypad_device);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
|
|||
IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
|
||||
|
||||
/* Configure pull down control */
|
||||
__raw_writel((__raw_readl(pupdctl1) & ~0x400),
|
||||
__raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
|
||||
pupdctl1);
|
||||
|
||||
mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
|
||||
|
|
|
@ -691,7 +691,6 @@ static struct emac_platform_data dm365_emac_pdata = {
|
|||
.ctrl_reg_offset = DM365_EMAC_CNTRL_OFFSET,
|
||||
.ctrl_mod_reg_offset = DM365_EMAC_CNTRL_MOD_OFFSET,
|
||||
.ctrl_ram_offset = DM365_EMAC_CNTRL_RAM_OFFSET,
|
||||
.mdio_reg_offset = DM365_EMAC_MDIO_OFFSET,
|
||||
.ctrl_ram_size = DM365_EMAC_CNTRL_RAM_SIZE,
|
||||
.version = EMAC_VERSION_2,
|
||||
};
|
||||
|
@ -699,7 +698,7 @@ static struct emac_platform_data dm365_emac_pdata = {
|
|||
static struct resource dm365_emac_resources[] = {
|
||||
{
|
||||
.start = DM365_EMAC_BASE,
|
||||
.end = DM365_EMAC_BASE + 0x47ff,
|
||||
.end = DM365_EMAC_BASE + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
|
@ -734,6 +733,21 @@ static struct platform_device dm365_emac_device = {
|
|||
.resource = dm365_emac_resources,
|
||||
};
|
||||
|
||||
static struct resource dm365_mdio_resources[] = {
|
||||
{
|
||||
.start = DM365_EMAC_MDIO_BASE,
|
||||
.end = DM365_EMAC_MDIO_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dm365_mdio_device = {
|
||||
.name = "davinci_mdio",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(dm365_mdio_resources),
|
||||
.resource = dm365_mdio_resources,
|
||||
};
|
||||
|
||||
static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
|
||||
[IRQ_VDINT0] = 2,
|
||||
[IRQ_VDINT1] = 6,
|
||||
|
@ -1219,7 +1233,12 @@ static int __init dm365_init_devices(void)
|
|||
|
||||
davinci_cfg_reg(DM365_INT_EDMA_CC);
|
||||
platform_device_register(&dm365_edma_device);
|
||||
|
||||
platform_device_register(&dm365_mdio_device);
|
||||
platform_device_register(&dm365_emac_device);
|
||||
clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
|
||||
NULL, &dm365_emac_device.dev);
|
||||
|
||||
/* Add isif clock alias */
|
||||
clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
|
||||
platform_device_register(&dm365_vpss_device);
|
||||
|
|
|
@ -322,7 +322,6 @@ static struct emac_platform_data dm644x_emac_pdata = {
|
|||
.ctrl_reg_offset = DM644X_EMAC_CNTRL_OFFSET,
|
||||
.ctrl_mod_reg_offset = DM644X_EMAC_CNTRL_MOD_OFFSET,
|
||||
.ctrl_ram_offset = DM644X_EMAC_CNTRL_RAM_OFFSET,
|
||||
.mdio_reg_offset = DM644X_EMAC_MDIO_OFFSET,
|
||||
.ctrl_ram_size = DM644X_EMAC_CNTRL_RAM_SIZE,
|
||||
.version = EMAC_VERSION_1,
|
||||
};
|
||||
|
@ -330,7 +329,7 @@ static struct emac_platform_data dm644x_emac_pdata = {
|
|||
static struct resource dm644x_emac_resources[] = {
|
||||
{
|
||||
.start = DM644X_EMAC_BASE,
|
||||
.end = DM644X_EMAC_BASE + 0x47ff,
|
||||
.end = DM644X_EMAC_BASE + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
|
@ -350,6 +349,21 @@ static struct platform_device dm644x_emac_device = {
|
|||
.resource = dm644x_emac_resources,
|
||||
};
|
||||
|
||||
static struct resource dm644x_mdio_resources[] = {
|
||||
{
|
||||
.start = DM644X_EMAC_MDIO_BASE,
|
||||
.end = DM644X_EMAC_MDIO_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dm644x_mdio_device = {
|
||||
.name = "davinci_mdio",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(dm644x_mdio_resources),
|
||||
.resource = dm644x_mdio_resources,
|
||||
};
|
||||
|
||||
/*
|
||||
* Device specific mux setup
|
||||
*
|
||||
|
@ -776,7 +790,12 @@ static int __init dm644x_init_devices(void)
|
|||
clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
|
||||
clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
|
||||
platform_device_register(&dm644x_edma_device);
|
||||
|
||||
platform_device_register(&dm644x_mdio_device);
|
||||
platform_device_register(&dm644x_emac_device);
|
||||
clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
|
||||
NULL, &dm644x_emac_device.dev);
|
||||
|
||||
platform_device_register(&dm644x_vpss_device);
|
||||
platform_device_register(&dm644x_ccdc_dev);
|
||||
platform_device_register(&vpfe_capture_dev);
|
||||
|
|
|
@ -358,7 +358,6 @@ static struct emac_platform_data dm646x_emac_pdata = {
|
|||
.ctrl_reg_offset = DM646X_EMAC_CNTRL_OFFSET,
|
||||
.ctrl_mod_reg_offset = DM646X_EMAC_CNTRL_MOD_OFFSET,
|
||||
.ctrl_ram_offset = DM646X_EMAC_CNTRL_RAM_OFFSET,
|
||||
.mdio_reg_offset = DM646X_EMAC_MDIO_OFFSET,
|
||||
.ctrl_ram_size = DM646X_EMAC_CNTRL_RAM_SIZE,
|
||||
.version = EMAC_VERSION_2,
|
||||
};
|
||||
|
@ -366,7 +365,7 @@ static struct emac_platform_data dm646x_emac_pdata = {
|
|||
static struct resource dm646x_emac_resources[] = {
|
||||
{
|
||||
.start = DM646X_EMAC_BASE,
|
||||
.end = DM646X_EMAC_BASE + 0x47ff,
|
||||
.end = DM646X_EMAC_BASE + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
|
@ -401,6 +400,21 @@ static struct platform_device dm646x_emac_device = {
|
|||
.resource = dm646x_emac_resources,
|
||||
};
|
||||
|
||||
static struct resource dm646x_mdio_resources[] = {
|
||||
{
|
||||
.start = DM646X_EMAC_MDIO_BASE,
|
||||
.end = DM646X_EMAC_MDIO_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device dm646x_mdio_device = {
|
||||
.name = "davinci_mdio",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(dm646x_mdio_resources),
|
||||
.resource = dm646x_mdio_resources,
|
||||
};
|
||||
|
||||
/*
|
||||
* Device specific mux setup
|
||||
*
|
||||
|
@ -896,7 +910,11 @@ static int __init dm646x_init_devices(void)
|
|||
if (!cpu_is_davinci_dm646x())
|
||||
return 0;
|
||||
|
||||
platform_device_register(&dm646x_mdio_device);
|
||||
platform_device_register(&dm646x_emac_device);
|
||||
clk_add_alias(NULL, dev_name(&dm646x_mdio_device.dev),
|
||||
NULL, &dm646x_emac_device.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(dm646x_init_devices);
|
||||
|
|
|
@ -354,10 +354,12 @@ static int irq2ctlr(int irq)
|
|||
static irqreturn_t dma_irq_handler(int irq, void *data)
|
||||
{
|
||||
int i;
|
||||
unsigned ctlr;
|
||||
int ctlr;
|
||||
unsigned int cnt = 0;
|
||||
|
||||
ctlr = irq2ctlr(irq);
|
||||
if (ctlr < 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(data, "dma_irq_handler\n");
|
||||
|
||||
|
@ -408,10 +410,12 @@ static irqreturn_t dma_irq_handler(int irq, void *data)
|
|||
static irqreturn_t dma_ccerr_handler(int irq, void *data)
|
||||
{
|
||||
int i;
|
||||
unsigned ctlr;
|
||||
int ctlr;
|
||||
unsigned int cnt = 0;
|
||||
|
||||
ctlr = irq2ctlr(irq);
|
||||
if (ctlr < 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(data, "dma_ccerr_handler\n");
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* TI DaVinci AEMIF support
|
||||
*
|
||||
* Copyright 2010 (C) Texas Instruments, Inc. http://www.ti.com/
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
#ifndef _MACH_DAVINCI_AEMIF_H
|
||||
#define _MACH_DAVINCI_AEMIF_H
|
||||
|
||||
#define NRCSR_OFFSET 0x00
|
||||
#define AWCCR_OFFSET 0x04
|
||||
#define A1CR_OFFSET 0x10
|
||||
|
||||
#define ACR_ASIZE_MASK 0x3
|
||||
#define ACR_EW_MASK BIT(30)
|
||||
#define ACR_SS_MASK BIT(31)
|
||||
|
||||
/* All timings in nanoseconds */
|
||||
struct davinci_aemif_timing {
|
||||
u8 wsetup;
|
||||
u8 wstrobe;
|
||||
u8 whold;
|
||||
|
||||
u8 rsetup;
|
||||
u8 rstrobe;
|
||||
u8 rhold;
|
||||
|
||||
u8 ta;
|
||||
};
|
||||
|
||||
int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
|
||||
void __iomem *base, unsigned cs);
|
||||
#endif
|
|
@ -76,9 +76,10 @@ int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
|
|||
int da8xx_register_emac(void);
|
||||
int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
|
||||
int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
|
||||
int da850_register_mmcsd1(struct davinci_mmc_config *config);
|
||||
void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
|
||||
int da8xx_register_rtc(void);
|
||||
int da850_register_cpufreq(void);
|
||||
int da850_register_cpufreq(char *async_clk);
|
||||
int da8xx_register_cpuidle(void);
|
||||
void __iomem * __init da8xx_get_mem_ctlr(void);
|
||||
int da850_register_pm(struct platform_device *pdev);
|
||||
|
@ -121,11 +122,9 @@ extern const short da850_uart2_pins[];
|
|||
extern const short da850_i2c0_pins[];
|
||||
extern const short da850_i2c1_pins[];
|
||||
extern const short da850_cpgmac_pins[];
|
||||
extern const short da850_rmii_pins[];
|
||||
extern const short da850_mcasp_pins[];
|
||||
extern const short da850_lcdcntl_pins[];
|
||||
extern const short da850_mmcsd0_pins[];
|
||||
extern const short da850_nand_pins[];
|
||||
extern const short da850_nor_pins[];
|
||||
extern const short da850_emif25_pins[];
|
||||
|
||||
#endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
#include <media/davinci/vpfe_capture.h>
|
||||
|
||||
#define DM365_EMAC_BASE (0x01D07000)
|
||||
#define DM365_EMAC_MDIO_BASE (DM365_EMAC_BASE + 0x4000)
|
||||
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
|
||||
#define DM365_EMAC_CNTRL_MOD_OFFSET (0x3000)
|
||||
#define DM365_EMAC_CNTRL_RAM_OFFSET (0x1000)
|
||||
#define DM365_EMAC_MDIO_OFFSET (0x4000)
|
||||
#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
|
||||
|
||||
/* Base of key scan register bank */
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
#include <media/davinci/vpfe_capture.h>
|
||||
|
||||
#define DM644X_EMAC_BASE (0x01C80000)
|
||||
#define DM644X_EMAC_MDIO_BASE (DM644X_EMAC_BASE + 0x4000)
|
||||
#define DM644X_EMAC_CNTRL_OFFSET (0x0000)
|
||||
#define DM644X_EMAC_CNTRL_MOD_OFFSET (0x1000)
|
||||
#define DM644X_EMAC_CNTRL_RAM_OFFSET (0x2000)
|
||||
#define DM644X_EMAC_MDIO_OFFSET (0x4000)
|
||||
#define DM644X_EMAC_CNTRL_RAM_SIZE (0x2000)
|
||||
|
||||
#define DM644X_ASYNC_EMIF_CONTROL_BASE 0x01E00000
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
#include <linux/davinci_emac.h>
|
||||
|
||||
#define DM646X_EMAC_BASE (0x01C80000)
|
||||
#define DM646X_EMAC_MDIO_BASE (DM646X_EMAC_BASE + 0x4000)
|
||||
#define DM646X_EMAC_CNTRL_OFFSET (0x0000)
|
||||
#define DM646X_EMAC_CNTRL_MOD_OFFSET (0x1000)
|
||||
#define DM646X_EMAC_CNTRL_RAM_OFFSET (0x2000)
|
||||
#define DM646X_EMAC_MDIO_OFFSET (0x4000)
|
||||
#define DM646X_EMAC_CNTRL_RAM_SIZE (0x2000)
|
||||
|
||||
#define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
#define NRCSR_OFFSET 0x00
|
||||
#define AWCCR_OFFSET 0x04
|
||||
#define A1CR_OFFSET 0x10
|
||||
#define NANDFCR_OFFSET 0x60
|
||||
#define NANDFSR_OFFSET 0x64
|
||||
#define NANDF1ECC_OFFSET 0x70
|
||||
|
@ -83,6 +80,9 @@ struct davinci_nand_pdata { /* platform_data */
|
|||
/* Main and mirror bbt descriptor overrides */
|
||||
struct nand_bbt_descr *bbt_td;
|
||||
struct nand_bbt_descr *bbt_md;
|
||||
|
||||
/* Access timings */
|
||||
struct davinci_aemif_timing *timing;
|
||||
};
|
||||
|
||||
#endif /* __ARCH_ARM_DAVINCI_NAND_H */
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
#define DA8XX_LPSC1_UART2 13
|
||||
#define DA8XX_LPSC1_LCDC 16
|
||||
#define DA8XX_LPSC1_PWM 17
|
||||
#define DA850_LPSC1_MMC_SD1 18
|
||||
#define DA8XX_LPSC1_ECAP 20
|
||||
#define DA830_LPSC1_EQEP 21
|
||||
#define DA850_LPSC1_TPTC2 21
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/nand.h>
|
||||
#include <mach/serial.h>
|
||||
|
@ -41,6 +43,7 @@ struct tnetv107x_device_info {
|
|||
struct davinci_uart_config *serial_config;
|
||||
struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */
|
||||
struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */
|
||||
struct matrix_keypad_platform_data *keypad_config;
|
||||
};
|
||||
|
||||
extern struct platform_device tnetv107x_wdt_device;
|
||||
|
|
|
@ -88,6 +88,8 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
|
|||
/* DA8xx boards */
|
||||
DEBUG_LL_DA8XX(davinci_da830_evm, 2);
|
||||
DEBUG_LL_DA8XX(davinci_da850_evm, 2);
|
||||
DEBUG_LL_DA8XX(mityomapl138, 1);
|
||||
DEBUG_LL_DA8XX(omapl138_hawkboard, 2);
|
||||
|
||||
/* TNETV107x boards */
|
||||
DEBUG_LL_TNETV107X(tnetv107x, 1);
|
||||
|
|
|
@ -104,7 +104,7 @@ static u32 pll_ext_freq[] = {
|
|||
};
|
||||
|
||||
/* PSC control registers */
|
||||
static u32 psc_regs[] __initconst = { TNETV107X_PSC_BASE };
|
||||
static u32 psc_regs[] = { TNETV107X_PSC_BASE };
|
||||
|
||||
/* Host map for interrupt controller */
|
||||
static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 };
|
||||
|
@ -581,7 +581,14 @@ static struct davinci_id ids[] = {
|
|||
.part_no = 0xb8a1,
|
||||
.manufacturer = 0x017,
|
||||
.cpu_id = DAVINCI_CPU_ID_TNETV107X,
|
||||
.name = "tnetv107x rev1.0",
|
||||
.name = "tnetv107x rev 1.0",
|
||||
},
|
||||
{
|
||||
.variant = 0x1,
|
||||
.part_no = 0xb8a1,
|
||||
.manufacturer = 0x017,
|
||||
.cpu_id = DAVINCI_CPU_ID_TNETV107X,
|
||||
.name = "tnetv107x rev 1.1/1.2",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
|
@ -38,19 +39,37 @@
|
|||
|
||||
#include "mux.h"
|
||||
|
||||
#define AM35XX_EVM_PHY_MASK (0xF)
|
||||
#define AM35XX_EVM_MDIO_FREQUENCY (1000000)
|
||||
|
||||
static struct mdio_platform_data am3517_evm_mdio_pdata = {
|
||||
.bus_freq = AM35XX_EVM_MDIO_FREQUENCY,
|
||||
};
|
||||
|
||||
static struct resource am3517_mdio_resources[] = {
|
||||
{
|
||||
.start = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
|
||||
.end = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
|
||||
SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device am3517_mdio_device = {
|
||||
.name = "davinci_mdio",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(am3517_mdio_resources),
|
||||
.resource = am3517_mdio_resources,
|
||||
.dev.platform_data = &am3517_evm_mdio_pdata,
|
||||
};
|
||||
|
||||
static struct emac_platform_data am3517_evm_emac_pdata = {
|
||||
.phy_mask = AM35XX_EVM_PHY_MASK,
|
||||
.mdio_max_freq = AM35XX_EVM_MDIO_FREQUENCY,
|
||||
.rmii_en = 1,
|
||||
};
|
||||
|
||||
static struct resource am3517_emac_resources[] = {
|
||||
{
|
||||
.start = AM35XX_IPSS_EMAC_BASE,
|
||||
.end = AM35XX_IPSS_EMAC_BASE + 0x3FFFF,
|
||||
.end = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
|
@ -113,7 +132,6 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
|
|||
pdata->ctrl_reg_offset = AM35XX_EMAC_CNTRL_OFFSET;
|
||||
pdata->ctrl_mod_reg_offset = AM35XX_EMAC_CNTRL_MOD_OFFSET;
|
||||
pdata->ctrl_ram_offset = AM35XX_EMAC_CNTRL_RAM_OFFSET;
|
||||
pdata->mdio_reg_offset = AM35XX_EMAC_MDIO_OFFSET;
|
||||
pdata->ctrl_ram_size = AM35XX_EMAC_CNTRL_RAM_SIZE;
|
||||
pdata->version = EMAC_VERSION_2;
|
||||
pdata->hw_ram_addr = AM35XX_EMAC_HW_RAM_ADDR;
|
||||
|
@ -121,6 +139,9 @@ void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
|
|||
pdata->interrupt_disable = am3517_disable_ethernet_int;
|
||||
am3517_emac_device.dev.platform_data = pdata;
|
||||
platform_device_register(&am3517_emac_device);
|
||||
platform_device_register(&am3517_mdio_device);
|
||||
clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
|
||||
NULL, &am3517_emac_device.dev);
|
||||
|
||||
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
|
||||
regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
|
||||
|
|
|
@ -443,6 +443,15 @@ config KEYBOARD_OMAP4
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called omap4-keypad.
|
||||
|
||||
config KEYBOARD_TNETV107X
|
||||
tristate "TI TNETV107X keypad support"
|
||||
depends on ARCH_DAVINCI_TNETV107X
|
||||
help
|
||||
Say Y here if you want to use the TNETV107X keypad.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tnetv107x-keypad.
|
||||
|
||||
config KEYBOARD_TWL4030
|
||||
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
|
||||
depends on TWL4030_CORE
|
||||
|
|
|
@ -40,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
|
|||
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* Texas Instruments TNETV107X Keypad Driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#define BITS(x) (BIT(x) - 1)
|
||||
|
||||
#define KEYPAD_ROWS 9
|
||||
#define KEYPAD_COLS 9
|
||||
|
||||
#define DEBOUNCE_MIN 0x400ul
|
||||
#define DEBOUNCE_MAX 0x3ffffffful
|
||||
|
||||
struct keypad_regs {
|
||||
u32 rev;
|
||||
u32 mode;
|
||||
u32 mask;
|
||||
u32 pol;
|
||||
u32 dclock;
|
||||
u32 rclock;
|
||||
u32 stable_cnt;
|
||||
u32 in_en;
|
||||
u32 out;
|
||||
u32 out_en;
|
||||
u32 in;
|
||||
u32 lock;
|
||||
u32 pres[3];
|
||||
};
|
||||
|
||||
#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg)
|
||||
#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg)
|
||||
|
||||
struct keypad_data {
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
struct keypad_regs __iomem *regs;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
spinlock_t lock;
|
||||
u32 irq_press;
|
||||
u32 irq_release;
|
||||
int rows, cols, row_shift;
|
||||
int debounce_ms, active_low;
|
||||
u32 prev_keys[3];
|
||||
unsigned short keycodes[];
|
||||
};
|
||||
|
||||
static irqreturn_t keypad_irq(int irq, void *data)
|
||||
{
|
||||
struct keypad_data *kp = data;
|
||||
int i, bit, val, row, col, code;
|
||||
unsigned long flags;
|
||||
u32 curr_keys[3];
|
||||
u32 change;
|
||||
|
||||
spin_lock_irqsave(&kp->lock, flags);
|
||||
|
||||
memset(curr_keys, 0, sizeof(curr_keys));
|
||||
if (irq == kp->irq_press)
|
||||
for (i = 0; i < 3; i++)
|
||||
curr_keys[i] = keypad_read(kp, pres[i]);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
change = curr_keys[i] ^ kp->prev_keys[i];
|
||||
|
||||
while (change) {
|
||||
bit = fls(change) - 1;
|
||||
change ^= BIT(bit);
|
||||
val = curr_keys[i] & BIT(bit);
|
||||
bit += i * 32;
|
||||
row = bit / KEYPAD_COLS;
|
||||
col = bit % KEYPAD_COLS;
|
||||
|
||||
code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
|
||||
input_event(kp->input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(kp->input_dev, kp->keycodes[code],
|
||||
val);
|
||||
}
|
||||
}
|
||||
input_sync(kp->input_dev);
|
||||
memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys));
|
||||
|
||||
if (irq == kp->irq_press)
|
||||
keypad_write(kp, lock, 0); /* Allow hardware updates */
|
||||
|
||||
spin_unlock_irqrestore(&kp->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int keypad_start(struct input_dev *dev)
|
||||
{
|
||||
struct keypad_data *kp = input_get_drvdata(dev);
|
||||
unsigned long mask, debounce, clk_rate_khz;
|
||||
unsigned long flags;
|
||||
|
||||
clk_enable(kp->clk);
|
||||
clk_rate_khz = clk_get_rate(kp->clk) / 1000;
|
||||
|
||||
spin_lock_irqsave(&kp->lock, flags);
|
||||
|
||||
/* Initialize device registers */
|
||||
keypad_write(kp, mode, 0);
|
||||
|
||||
mask = BITS(kp->rows) << KEYPAD_COLS;
|
||||
mask |= BITS(kp->cols);
|
||||
keypad_write(kp, mask, ~mask);
|
||||
|
||||
keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff);
|
||||
keypad_write(kp, stable_cnt, 3);
|
||||
|
||||
debounce = kp->debounce_ms * clk_rate_khz;
|
||||
debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX);
|
||||
keypad_write(kp, dclock, debounce);
|
||||
keypad_write(kp, rclock, 4 * debounce);
|
||||
|
||||
keypad_write(kp, in_en, 1);
|
||||
|
||||
spin_unlock_irqrestore(&kp->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keypad_stop(struct input_dev *dev)
|
||||
{
|
||||
struct keypad_data *kp = input_get_drvdata(dev);
|
||||
|
||||
synchronize_irq(kp->irq_press);
|
||||
synchronize_irq(kp->irq_release);
|
||||
clk_disable(kp->clk);
|
||||
}
|
||||
|
||||
static int __devinit keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct matrix_keypad_platform_data *pdata;
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct keypad_data *kp;
|
||||
int error = 0, sz, row_shift;
|
||||
u32 rev = 0;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(dev, "cannot find device data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keymap_data = pdata->keymap_data;
|
||||
if (!keymap_data) {
|
||||
dev_err(dev, "cannot find keymap data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
row_shift = get_count_order(pdata->num_col_gpios);
|
||||
sz = offsetof(struct keypad_data, keycodes);
|
||||
sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]);
|
||||
kp = kzalloc(sz, GFP_KERNEL);
|
||||
if (!kp) {
|
||||
dev_err(dev, "cannot allocate device info\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kp->dev = dev;
|
||||
kp->rows = pdata->num_row_gpios;
|
||||
kp->cols = pdata->num_col_gpios;
|
||||
kp->row_shift = row_shift;
|
||||
platform_set_drvdata(pdev, kp);
|
||||
spin_lock_init(&kp->lock);
|
||||
|
||||
kp->irq_press = platform_get_irq_byname(pdev, "press");
|
||||
kp->irq_release = platform_get_irq_byname(pdev, "release");
|
||||
if (kp->irq_press < 0 || kp->irq_release < 0) {
|
||||
dev_err(dev, "cannot determine device interrupts\n");
|
||||
error = -ENODEV;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!kp->res) {
|
||||
dev_err(dev, "cannot determine register area\n");
|
||||
error = -ENODEV;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
if (!request_mem_region(kp->res->start, resource_size(kp->res),
|
||||
pdev->name)) {
|
||||
dev_err(dev, "cannot claim register memory\n");
|
||||
kp->res = NULL;
|
||||
error = -EINVAL;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
kp->regs = ioremap(kp->res->start, resource_size(kp->res));
|
||||
if (!kp->regs) {
|
||||
dev_err(dev, "cannot map register memory\n");
|
||||
error = -ENOMEM;
|
||||
goto error_map;
|
||||
}
|
||||
|
||||
kp->clk = clk_get(dev, NULL);
|
||||
if (!kp->clk) {
|
||||
dev_err(dev, "cannot claim device clock\n");
|
||||
error = -EINVAL;
|
||||
goto error_clk;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0,
|
||||
dev_name(dev), kp);
|
||||
if (error < 0) {
|
||||
dev_err(kp->dev, "Could not allocate keypad press key irq\n");
|
||||
goto error_irq_press;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0,
|
||||
dev_name(dev), kp);
|
||||
if (error < 0) {
|
||||
dev_err(kp->dev, "Could not allocate keypad release key irq\n");
|
||||
goto error_irq_release;
|
||||
}
|
||||
|
||||
kp->input_dev = input_allocate_device();
|
||||
if (!kp->input_dev) {
|
||||
dev_err(dev, "cannot allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto error_input;
|
||||
}
|
||||
input_set_drvdata(kp->input_dev, kp);
|
||||
|
||||
kp->input_dev->name = pdev->name;
|
||||
kp->input_dev->dev.parent = &pdev->dev;
|
||||
kp->input_dev->open = keypad_start;
|
||||
kp->input_dev->close = keypad_stop;
|
||||
kp->input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
if (!pdata->no_autorepeat)
|
||||
kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
|
||||
|
||||
clk_enable(kp->clk);
|
||||
rev = keypad_read(kp, rev);
|
||||
kp->input_dev->id.bustype = BUS_HOST;
|
||||
kp->input_dev->id.product = ((rev >> 8) & 0x07);
|
||||
kp->input_dev->id.version = ((rev >> 16) & 0xfff);
|
||||
clk_disable(kp->clk);
|
||||
|
||||
kp->input_dev->keycode = kp->keycodes;
|
||||
kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
|
||||
kp->input_dev->keycodemax = kp->rows << kp->row_shift;
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
|
||||
kp->input_dev->keybit);
|
||||
|
||||
input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
error = input_register_device(kp->input_dev);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Could not register input device\n");
|
||||
goto error_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
error_reg:
|
||||
input_free_device(kp->input_dev);
|
||||
error_input:
|
||||
free_irq(kp->irq_release, kp);
|
||||
error_irq_release:
|
||||
free_irq(kp->irq_press, kp);
|
||||
error_irq_press:
|
||||
clk_put(kp->clk);
|
||||
error_clk:
|
||||
iounmap(kp->regs);
|
||||
error_map:
|
||||
release_mem_region(kp->res->start, resource_size(kp->res));
|
||||
error_res:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(kp);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit keypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct keypad_data *kp = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(kp->irq_press, kp);
|
||||
free_irq(kp->irq_release, kp);
|
||||
input_unregister_device(kp->input_dev);
|
||||
clk_put(kp->clk);
|
||||
iounmap(kp->regs);
|
||||
release_mem_region(kp->res->start, resource_size(kp->res));
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(kp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver keypad_driver = {
|
||||
.probe = keypad_probe,
|
||||
.remove = __devexit_p(keypad_remove),
|
||||
.driver.name = "tnetv107x-keypad",
|
||||
.driver.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init keypad_init(void)
|
||||
{
|
||||
return platform_driver_register(&keypad_driver);
|
||||
}
|
||||
|
||||
static void __exit keypad_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&keypad_driver);
|
||||
}
|
||||
|
||||
module_init(keypad_init);
|
||||
module_exit(keypad_exit);
|
||||
|
||||
MODULE_AUTHOR("Cyril Chemparathy");
|
||||
MODULE_DESCRIPTION("TNETV107X Keypad Driver");
|
||||
MODULE_ALIAS("platform: tnetv107x-keypad");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -362,6 +362,15 @@ config TOUCHSCREEN_MIGOR
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called migor_ts.
|
||||
|
||||
config TOUCHSCREEN_TNETV107X
|
||||
tristate "TI TNETV107X touchscreen support"
|
||||
depends on ARCH_DAVINCI_TNETV107X
|
||||
help
|
||||
Say Y here if you want to use the TNETV107X touchscreen.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tnetv107x-ts.
|
||||
|
||||
config TOUCHSCREEN_TOUCHRIGHT
|
||||
tristate "Touchright serial touchscreen"
|
||||
select SERIO
|
||||
|
|
|
@ -40,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Texas Instruments TNETV107X Touchscreen Driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <mach/tnetv107x.h>
|
||||
|
||||
#define TSC_PENUP_POLL (HZ / 5)
|
||||
#define IDLE_TIMEOUT 100 /* msec */
|
||||
|
||||
/*
|
||||
* The first and last samples of a touch interval are usually garbage and need
|
||||
* to be filtered out with these devices. The following definitions control
|
||||
* the number of samples skipped.
|
||||
*/
|
||||
#define TSC_HEAD_SKIP 1
|
||||
#define TSC_TAIL_SKIP 1
|
||||
#define TSC_SKIP (TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
|
||||
#define TSC_SAMPLES (TSC_SKIP + 1)
|
||||
|
||||
/* Register Offsets */
|
||||
struct tsc_regs {
|
||||
u32 rev;
|
||||
u32 tscm;
|
||||
u32 bwcm;
|
||||
u32 swc;
|
||||
u32 adcchnl;
|
||||
u32 adcdata;
|
||||
u32 chval[4];
|
||||
};
|
||||
|
||||
/* TSC Mode Configuration Register (tscm) bits */
|
||||
#define WMODE BIT(0)
|
||||
#define TSKIND BIT(1)
|
||||
#define ZMEASURE_EN BIT(2)
|
||||
#define IDLE BIT(3)
|
||||
#define TSC_EN BIT(4)
|
||||
#define STOP BIT(5)
|
||||
#define ONE_SHOT BIT(6)
|
||||
#define SINGLE BIT(7)
|
||||
#define AVG BIT(8)
|
||||
#define AVGNUM(x) (((x) & 0x03) << 9)
|
||||
#define PVSTC(x) (((x) & 0x07) << 11)
|
||||
#define PON BIT(14)
|
||||
#define PONBG BIT(15)
|
||||
#define AFERST BIT(16)
|
||||
|
||||
/* ADC DATA Capture Register bits */
|
||||
#define DATA_VALID BIT(16)
|
||||
|
||||
/* Register Access Macros */
|
||||
#define tsc_read(ts, reg) __raw_readl(&(ts)->regs->reg)
|
||||
#define tsc_write(ts, reg, val) __raw_writel(val, &(ts)->regs->reg);
|
||||
#define tsc_set_bits(ts, reg, val) \
|
||||
tsc_write(ts, reg, tsc_read(ts, reg) | (val))
|
||||
#define tsc_clr_bits(ts, reg, val) \
|
||||
tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
|
||||
|
||||
struct sample {
|
||||
int x, y, p;
|
||||
};
|
||||
|
||||
struct tsc_data {
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
struct tsc_regs __iomem *regs;
|
||||
struct timer_list timer;
|
||||
spinlock_t lock;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
int sample_count;
|
||||
struct sample samples[TSC_SAMPLES];
|
||||
int tsc_irq;
|
||||
};
|
||||
|
||||
static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
|
||||
{
|
||||
int x, y, z1, z2, t, p = 0;
|
||||
u32 val;
|
||||
|
||||
val = tsc_read(ts, chval[0]);
|
||||
if (val & DATA_VALID)
|
||||
x = val & 0xffff;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
y = tsc_read(ts, chval[1]) & 0xffff;
|
||||
z1 = tsc_read(ts, chval[2]) & 0xffff;
|
||||
z2 = tsc_read(ts, chval[3]) & 0xffff;
|
||||
|
||||
if (z1) {
|
||||
t = ((600 * x) * (z2 - z1));
|
||||
p = t / (u32) (z1 << 12);
|
||||
if (p < 0)
|
||||
p = 0;
|
||||
}
|
||||
|
||||
sample->x = x;
|
||||
sample->y = y;
|
||||
sample->p = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsc_poll(unsigned long data)
|
||||
{
|
||||
struct tsc_data *ts = (struct tsc_data *)data;
|
||||
unsigned long flags;
|
||||
int i, val, x, y, p;
|
||||
|
||||
spin_lock_irqsave(&ts->lock, flags);
|
||||
|
||||
if (ts->sample_count >= TSC_SKIP) {
|
||||
input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
|
||||
input_report_key(ts->input_dev, BTN_TOUCH, 0);
|
||||
input_sync(ts->input_dev);
|
||||
} else if (ts->sample_count > 0) {
|
||||
/*
|
||||
* A touch event lasted less than our skip count. Salvage and
|
||||
* report anyway.
|
||||
*/
|
||||
for (i = 0, val = 0; i < ts->sample_count; i++)
|
||||
val += ts->samples[i].x;
|
||||
x = val / ts->sample_count;
|
||||
|
||||
for (i = 0, val = 0; i < ts->sample_count; i++)
|
||||
val += ts->samples[i].y;
|
||||
y = val / ts->sample_count;
|
||||
|
||||
for (i = 0, val = 0; i < ts->sample_count; i++)
|
||||
val += ts->samples[i].p;
|
||||
p = val / ts->sample_count;
|
||||
|
||||
input_report_abs(ts->input_dev, ABS_X, x);
|
||||
input_report_abs(ts->input_dev, ABS_Y, y);
|
||||
input_report_abs(ts->input_dev, ABS_PRESSURE, p);
|
||||
input_report_key(ts->input_dev, BTN_TOUCH, 1);
|
||||
input_sync(ts->input_dev);
|
||||
}
|
||||
|
||||
ts->sample_count = 0;
|
||||
|
||||
spin_unlock_irqrestore(&ts->lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t tsc_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct tsc_data *ts = (struct tsc_data *)dev_id;
|
||||
struct sample *sample;
|
||||
int index;
|
||||
|
||||
spin_lock(&ts->lock);
|
||||
|
||||
index = ts->sample_count % TSC_SAMPLES;
|
||||
sample = &ts->samples[index];
|
||||
if (tsc_read_sample(ts, sample) < 0)
|
||||
goto out;
|
||||
|
||||
if (++ts->sample_count >= TSC_SKIP) {
|
||||
index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
|
||||
sample = &ts->samples[index];
|
||||
|
||||
input_report_abs(ts->input_dev, ABS_X, sample->x);
|
||||
input_report_abs(ts->input_dev, ABS_Y, sample->y);
|
||||
input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
|
||||
if (ts->sample_count == TSC_SKIP)
|
||||
input_report_key(ts->input_dev, BTN_TOUCH, 1);
|
||||
input_sync(ts->input_dev);
|
||||
}
|
||||
mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
|
||||
out:
|
||||
spin_unlock(&ts->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tsc_start(struct input_dev *dev)
|
||||
{
|
||||
struct tsc_data *ts = input_get_drvdata(dev);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
|
||||
u32 val;
|
||||
|
||||
clk_enable(ts->clk);
|
||||
|
||||
/* Go to idle mode, before any initialization */
|
||||
while (time_after(timeout, jiffies)) {
|
||||
if (tsc_read(ts, tscm) & IDLE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_before(timeout, jiffies)) {
|
||||
dev_warn(ts->dev, "timeout waiting for idle\n");
|
||||
clk_disable(ts->clk);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Configure TSC Control register*/
|
||||
val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
|
||||
tsc_write(ts, tscm, val);
|
||||
|
||||
/* Bring TSC out of reset: Clear AFE reset bit */
|
||||
val &= ~(AFERST);
|
||||
tsc_write(ts, tscm, val);
|
||||
|
||||
/* Configure all pins for hardware control*/
|
||||
tsc_write(ts, bwcm, 0);
|
||||
|
||||
/* Finally enable the TSC */
|
||||
tsc_set_bits(ts, tscm, TSC_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsc_stop(struct input_dev *dev)
|
||||
{
|
||||
struct tsc_data *ts = input_get_drvdata(dev);
|
||||
|
||||
tsc_clr_bits(ts, tscm, TSC_EN);
|
||||
synchronize_irq(ts->tsc_irq);
|
||||
del_timer_sync(&ts->timer);
|
||||
clk_disable(ts->clk);
|
||||
}
|
||||
|
||||
static int __devinit tsc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tsc_data *ts;
|
||||
int error = 0;
|
||||
u32 rev = 0;
|
||||
|
||||
ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
|
||||
if (!ts) {
|
||||
dev_err(dev, "cannot allocate device info\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ts->dev = dev;
|
||||
spin_lock_init(&ts->lock);
|
||||
setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
|
||||
platform_set_drvdata(pdev, ts);
|
||||
|
||||
ts->tsc_irq = platform_get_irq(pdev, 0);
|
||||
if (ts->tsc_irq < 0) {
|
||||
dev_err(dev, "cannot determine device interrupt\n");
|
||||
error = -ENODEV;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!ts->res) {
|
||||
dev_err(dev, "cannot determine register area\n");
|
||||
error = -ENODEV;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
if (!request_mem_region(ts->res->start, resource_size(ts->res),
|
||||
pdev->name)) {
|
||||
dev_err(dev, "cannot claim register memory\n");
|
||||
ts->res = NULL;
|
||||
error = -EINVAL;
|
||||
goto error_res;
|
||||
}
|
||||
|
||||
ts->regs = ioremap(ts->res->start, resource_size(ts->res));
|
||||
if (!ts->regs) {
|
||||
dev_err(dev, "cannot map register memory\n");
|
||||
error = -ENOMEM;
|
||||
goto error_map;
|
||||
}
|
||||
|
||||
ts->clk = clk_get(dev, NULL);
|
||||
if (!ts->clk) {
|
||||
dev_err(dev, "cannot claim device clock\n");
|
||||
error = -EINVAL;
|
||||
goto error_clk;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
|
||||
dev_name(dev), ts);
|
||||
if (error < 0) {
|
||||
dev_err(ts->dev, "Could not allocate ts irq\n");
|
||||
goto error_irq;
|
||||
}
|
||||
|
||||
ts->input_dev = input_allocate_device();
|
||||
if (!ts->input_dev) {
|
||||
dev_err(dev, "cannot allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto error_input;
|
||||
}
|
||||
input_set_drvdata(ts->input_dev, ts);
|
||||
|
||||
ts->input_dev->name = pdev->name;
|
||||
ts->input_dev->id.bustype = BUS_HOST;
|
||||
ts->input_dev->dev.parent = &pdev->dev;
|
||||
ts->input_dev->open = tsc_start;
|
||||
ts->input_dev->close = tsc_stop;
|
||||
|
||||
clk_enable(ts->clk);
|
||||
rev = tsc_read(ts, rev);
|
||||
ts->input_dev->id.product = ((rev >> 8) & 0x07);
|
||||
ts->input_dev->id.version = ((rev >> 16) & 0xfff);
|
||||
clk_disable(ts->clk);
|
||||
|
||||
__set_bit(EV_KEY, ts->input_dev->evbit);
|
||||
__set_bit(EV_ABS, ts->input_dev->evbit);
|
||||
__set_bit(BTN_TOUCH, ts->input_dev->keybit);
|
||||
|
||||
input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
|
||||
input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
|
||||
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
|
||||
|
||||
error = input_register_device(ts->input_dev);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "failed input device registration\n");
|
||||
goto error_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_reg:
|
||||
input_free_device(ts->input_dev);
|
||||
error_input:
|
||||
free_irq(ts->tsc_irq, ts);
|
||||
error_irq:
|
||||
clk_put(ts->clk);
|
||||
error_clk:
|
||||
iounmap(ts->regs);
|
||||
error_map:
|
||||
release_mem_region(ts->res->start, resource_size(ts->res));
|
||||
error_res:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(ts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit tsc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tsc_data *ts = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(ts->input_dev);
|
||||
free_irq(ts->tsc_irq, ts);
|
||||
clk_put(ts->clk);
|
||||
iounmap(ts->regs);
|
||||
release_mem_region(ts->res->start, resource_size(ts->res));
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tsc_driver = {
|
||||
.probe = tsc_probe,
|
||||
.remove = __devexit_p(tsc_remove),
|
||||
.driver.name = "tnetv107x-ts",
|
||||
.driver.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init tsc_init(void)
|
||||
{
|
||||
return platform_driver_register(&tsc_driver);
|
||||
}
|
||||
|
||||
static void __exit tsc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tsc_driver);
|
||||
}
|
||||
|
||||
module_init(tsc_init);
|
||||
module_exit(tsc_exit);
|
||||
|
||||
MODULE_AUTHOR("Cyril Chemparathy");
|
||||
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
|
||||
MODULE_ALIAS("platform: tnetv107x-ts");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include <mach/nand.h>
|
||||
#include <mach/aemif.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
@ -74,6 +75,8 @@ struct davinci_nand_info {
|
|||
uint32_t mask_cle;
|
||||
|
||||
uint32_t core_chipsel;
|
||||
|
||||
struct davinci_aemif_timing *timing;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(davinci_nand_lock);
|
||||
|
@ -478,36 +481,6 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
|
|||
return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
|
||||
}
|
||||
|
||||
static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info)
|
||||
{
|
||||
uint32_t regval, a1cr;
|
||||
|
||||
/*
|
||||
* NAND FLASH timings @ PLL1 == 459 MHz
|
||||
* - AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz
|
||||
* - AEMIF.CLK period = 1/76.5 MHz = 13.1 ns
|
||||
*/
|
||||
regval = 0
|
||||
| (0 << 31) /* selectStrobe */
|
||||
| (0 << 30) /* extWait (never with NAND) */
|
||||
| (1 << 26) /* writeSetup 10 ns */
|
||||
| (3 << 20) /* writeStrobe 40 ns */
|
||||
| (1 << 17) /* writeHold 10 ns */
|
||||
| (0 << 13) /* readSetup 10 ns */
|
||||
| (3 << 7) /* readStrobe 60 ns */
|
||||
| (0 << 4) /* readHold 10 ns */
|
||||
| (3 << 2) /* turnAround ?? ns */
|
||||
| (0 << 0) /* asyncSize 8-bit bus */
|
||||
;
|
||||
a1cr = davinci_nand_readl(info, A1CR_OFFSET);
|
||||
if (a1cr != regval) {
|
||||
dev_dbg(info->dev, "Warning: NAND config: Set A1CR " \
|
||||
"reg to 0x%08x, was 0x%08x, should be done by " \
|
||||
"bootloader.\n", regval, a1cr);
|
||||
davinci_nand_writel(info, A1CR_OFFSET, regval);
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* An ECC layout for using 4-bit ECC with small-page flash, storing
|
||||
|
@ -611,6 +584,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
|||
info->chip.options = pdata->options;
|
||||
info->chip.bbt_td = pdata->bbt_td;
|
||||
info->chip.bbt_md = pdata->bbt_md;
|
||||
info->timing = pdata->timing;
|
||||
|
||||
info->ioaddr = (uint32_t __force) vaddr;
|
||||
|
||||
|
@ -688,15 +662,25 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
|||
goto err_clk_enable;
|
||||
}
|
||||
|
||||
/* EMIF timings should normally be set by the boot loader,
|
||||
* especially after boot-from-NAND. The *only* reason to
|
||||
* have this special casing for the DM6446 EVM is to work
|
||||
* with boot-from-NOR ... with CS0 manually re-jumpered
|
||||
* (after startup) so it addresses the NAND flash, not NOR.
|
||||
* Even for dev boards, that's unusually rude...
|
||||
/*
|
||||
* Setup Async configuration register in case we did not boot from
|
||||
* NAND and so bootloader did not bother to set it up.
|
||||
*/
|
||||
if (machine_is_davinci_evm())
|
||||
nand_dm6446evm_flash_init(info);
|
||||
val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4);
|
||||
|
||||
/* Extended Wait is not valid and Select Strobe mode is not used */
|
||||
val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK);
|
||||
if (info->chip.options & NAND_BUSWIDTH_16)
|
||||
val |= 0x1;
|
||||
|
||||
davinci_nand_writel(info, A1CR_OFFSET + info->core_chipsel * 4, val);
|
||||
|
||||
ret = davinci_aemif_setup_timing(info->timing, info->base,
|
||||
info->core_chipsel);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
|
||||
goto err_timing;
|
||||
}
|
||||
|
||||
spin_lock_irq(&davinci_nand_lock);
|
||||
|
||||
|
@ -809,6 +793,7 @@ syndrome_done:
|
|||
return 0;
|
||||
|
||||
err_scan:
|
||||
err_timing:
|
||||
clk_disable(info->clk);
|
||||
|
||||
err_clk_enable:
|
||||
|
|
|
@ -954,6 +954,8 @@ config NET_NETX
|
|||
config TI_DAVINCI_EMAC
|
||||
tristate "TI DaVinci EMAC Support"
|
||||
depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
|
||||
select TI_DAVINCI_MDIO
|
||||
select TI_DAVINCI_CPDMA
|
||||
select PHYLIB
|
||||
help
|
||||
This driver supports TI's DaVinci Ethernet .
|
||||
|
@ -961,6 +963,25 @@ config TI_DAVINCI_EMAC
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called davinci_emac_driver. This is recommended.
|
||||
|
||||
config TI_DAVINCI_MDIO
|
||||
tristate "TI DaVinci MDIO Support"
|
||||
depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
|
||||
select PHYLIB
|
||||
help
|
||||
This driver supports TI's DaVinci MDIO module.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called davinci_mdio. This is recommended.
|
||||
|
||||
config TI_DAVINCI_CPDMA
|
||||
tristate "TI DaVinci CPDMA Support"
|
||||
depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
|
||||
help
|
||||
This driver supports TI's DaVinci CPDMA dma engine.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called davinci_cpdma. This is recommended.
|
||||
|
||||
config DM9000
|
||||
tristate "DM9000 support"
|
||||
depends on ARM || BLACKFIN || MIPS
|
||||
|
|
|
@ -7,6 +7,8 @@ obj-$(CONFIG_MDIO) += mdio.o
|
|||
obj-$(CONFIG_PHYLIB) += phy/
|
||||
|
||||
obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
|
||||
obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
|
||||
obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
|
||||
|
||||
obj-$(CONFIG_E1000) += e1000/
|
||||
obj-$(CONFIG_E1000E) += e1000e/
|
||||
|
|
|
@ -0,0 +1,965 @@
|
|||
/*
|
||||
* Texas Instruments CPDMA Driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "davinci_cpdma.h"
|
||||
|
||||
/* DMA Registers */
|
||||
#define CPDMA_TXIDVER 0x00
|
||||
#define CPDMA_TXCONTROL 0x04
|
||||
#define CPDMA_TXTEARDOWN 0x08
|
||||
#define CPDMA_RXIDVER 0x10
|
||||
#define CPDMA_RXCONTROL 0x14
|
||||
#define CPDMA_SOFTRESET 0x1c
|
||||
#define CPDMA_RXTEARDOWN 0x18
|
||||
#define CPDMA_TXINTSTATRAW 0x80
|
||||
#define CPDMA_TXINTSTATMASKED 0x84
|
||||
#define CPDMA_TXINTMASKSET 0x88
|
||||
#define CPDMA_TXINTMASKCLEAR 0x8c
|
||||
#define CPDMA_MACINVECTOR 0x90
|
||||
#define CPDMA_MACEOIVECTOR 0x94
|
||||
#define CPDMA_RXINTSTATRAW 0xa0
|
||||
#define CPDMA_RXINTSTATMASKED 0xa4
|
||||
#define CPDMA_RXINTMASKSET 0xa8
|
||||
#define CPDMA_RXINTMASKCLEAR 0xac
|
||||
#define CPDMA_DMAINTSTATRAW 0xb0
|
||||
#define CPDMA_DMAINTSTATMASKED 0xb4
|
||||
#define CPDMA_DMAINTMASKSET 0xb8
|
||||
#define CPDMA_DMAINTMASKCLEAR 0xbc
|
||||
#define CPDMA_DMAINT_HOSTERR BIT(1)
|
||||
|
||||
/* the following exist only if has_ext_regs is set */
|
||||
#define CPDMA_DMACONTROL 0x20
|
||||
#define CPDMA_DMASTATUS 0x24
|
||||
#define CPDMA_RXBUFFOFS 0x28
|
||||
#define CPDMA_EM_CONTROL 0x2c
|
||||
|
||||
/* Descriptor mode bits */
|
||||
#define CPDMA_DESC_SOP BIT(31)
|
||||
#define CPDMA_DESC_EOP BIT(30)
|
||||
#define CPDMA_DESC_OWNER BIT(29)
|
||||
#define CPDMA_DESC_EOQ BIT(28)
|
||||
#define CPDMA_DESC_TD_COMPLETE BIT(27)
|
||||
#define CPDMA_DESC_PASS_CRC BIT(26)
|
||||
|
||||
#define CPDMA_TEARDOWN_VALUE 0xfffffffc
|
||||
|
||||
struct cpdma_desc {
|
||||
/* hardware fields */
|
||||
u32 hw_next;
|
||||
u32 hw_buffer;
|
||||
u32 hw_len;
|
||||
u32 hw_mode;
|
||||
/* software fields */
|
||||
void *sw_token;
|
||||
u32 sw_buffer;
|
||||
u32 sw_len;
|
||||
};
|
||||
|
||||
struct cpdma_desc_pool {
|
||||
u32 phys;
|
||||
void __iomem *iomap; /* ioremap map */
|
||||
void *cpumap; /* dma_alloc map */
|
||||
int desc_size, mem_size;
|
||||
int num_desc, used_desc;
|
||||
unsigned long *bitmap;
|
||||
struct device *dev;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum cpdma_state {
|
||||
CPDMA_STATE_IDLE,
|
||||
CPDMA_STATE_ACTIVE,
|
||||
CPDMA_STATE_TEARDOWN,
|
||||
};
|
||||
|
||||
const char *cpdma_state_str[] = { "idle", "active", "teardown" };
|
||||
|
||||
struct cpdma_ctlr {
|
||||
enum cpdma_state state;
|
||||
struct cpdma_params params;
|
||||
struct device *dev;
|
||||
struct cpdma_desc_pool *pool;
|
||||
spinlock_t lock;
|
||||
struct cpdma_chan *channels[2 * CPDMA_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct cpdma_chan {
|
||||
enum cpdma_state state;
|
||||
struct cpdma_ctlr *ctlr;
|
||||
int chan_num;
|
||||
spinlock_t lock;
|
||||
struct cpdma_desc __iomem *head, *tail;
|
||||
int count;
|
||||
void __iomem *hdp, *cp, *rxfree;
|
||||
u32 mask;
|
||||
cpdma_handler_fn handler;
|
||||
enum dma_data_direction dir;
|
||||
struct cpdma_chan_stats stats;
|
||||
/* offsets into dmaregs */
|
||||
int int_set, int_clear, td;
|
||||
};
|
||||
|
||||
/* The following make access to common cpdma_ctlr params more readable */
|
||||
#define dmaregs params.dmaregs
|
||||
#define num_chan params.num_chan
|
||||
|
||||
/* various accessors */
|
||||
#define dma_reg_read(ctlr, ofs) __raw_readl((ctlr)->dmaregs + (ofs))
|
||||
#define chan_read(chan, fld) __raw_readl((chan)->fld)
|
||||
#define desc_read(desc, fld) __raw_readl(&(desc)->fld)
|
||||
#define dma_reg_write(ctlr, ofs, v) __raw_writel(v, (ctlr)->dmaregs + (ofs))
|
||||
#define chan_write(chan, fld, v) __raw_writel(v, (chan)->fld)
|
||||
#define desc_write(desc, fld, v) __raw_writel((u32)(v), &(desc)->fld)
|
||||
|
||||
/*
|
||||
* Utility constructs for a cpdma descriptor pool. Some devices (e.g. davinci
|
||||
* emac) have dedicated on-chip memory for these descriptors. Some other
|
||||
* devices (e.g. cpsw switches) use plain old memory. Descriptor pools
|
||||
* abstract out these details
|
||||
*/
|
||||
static struct cpdma_desc_pool *
|
||||
cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align)
|
||||
{
|
||||
int bitmap_size;
|
||||
struct cpdma_desc_pool *pool;
|
||||
|
||||
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&pool->lock);
|
||||
|
||||
pool->dev = dev;
|
||||
pool->mem_size = size;
|
||||
pool->desc_size = ALIGN(sizeof(struct cpdma_desc), align);
|
||||
pool->num_desc = size / pool->desc_size;
|
||||
|
||||
bitmap_size = (pool->num_desc / BITS_PER_LONG) * sizeof(long);
|
||||
pool->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!pool->bitmap)
|
||||
goto fail;
|
||||
|
||||
if (phys) {
|
||||
pool->phys = phys;
|
||||
pool->iomap = ioremap(phys, size);
|
||||
} else {
|
||||
pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys,
|
||||
GFP_KERNEL);
|
||||
pool->iomap = (void __force __iomem *)pool->cpumap;
|
||||
}
|
||||
|
||||
if (pool->iomap)
|
||||
return pool;
|
||||
|
||||
fail:
|
||||
kfree(pool->bitmap);
|
||||
kfree(pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pool->lock, flags);
|
||||
WARN_ON(pool->used_desc);
|
||||
kfree(pool->bitmap);
|
||||
if (pool->cpumap) {
|
||||
dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap,
|
||||
pool->phys);
|
||||
} else {
|
||||
iounmap(pool->iomap);
|
||||
}
|
||||
spin_unlock_irqrestore(&pool->lock, flags);
|
||||
kfree(pool);
|
||||
}
|
||||
|
||||
static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool,
|
||||
struct cpdma_desc __iomem *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return 0;
|
||||
return pool->phys + (__force dma_addr_t)desc -
|
||||
(__force dma_addr_t)pool->iomap;
|
||||
}
|
||||
|
||||
static inline struct cpdma_desc __iomem *
|
||||
desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
|
||||
{
|
||||
return dma ? pool->iomap + dma - pool->phys : NULL;
|
||||
}
|
||||
|
||||
static struct cpdma_desc __iomem *
|
||||
cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
|
||||
{
|
||||
unsigned long flags;
|
||||
int index;
|
||||
struct cpdma_desc __iomem *desc = NULL;
|
||||
|
||||
spin_lock_irqsave(&pool->lock, flags);
|
||||
|
||||
index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
|
||||
num_desc, 0);
|
||||
if (index < pool->num_desc) {
|
||||
bitmap_set(pool->bitmap, index, num_desc);
|
||||
desc = pool->iomap + pool->desc_size * index;
|
||||
pool->used_desc++;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&pool->lock, flags);
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void cpdma_desc_free(struct cpdma_desc_pool *pool,
|
||||
struct cpdma_desc __iomem *desc, int num_desc)
|
||||
{
|
||||
unsigned long flags, index;
|
||||
|
||||
index = ((unsigned long)desc - (unsigned long)pool->iomap) /
|
||||
pool->desc_size;
|
||||
spin_lock_irqsave(&pool->lock, flags);
|
||||
bitmap_clear(pool->bitmap, index, num_desc);
|
||||
pool->used_desc--;
|
||||
spin_unlock_irqrestore(&pool->lock, flags);
|
||||
}
|
||||
|
||||
struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr;
|
||||
|
||||
ctlr = kzalloc(sizeof(*ctlr), GFP_KERNEL);
|
||||
if (!ctlr)
|
||||
return NULL;
|
||||
|
||||
ctlr->state = CPDMA_STATE_IDLE;
|
||||
ctlr->params = *params;
|
||||
ctlr->dev = params->dev;
|
||||
spin_lock_init(&ctlr->lock);
|
||||
|
||||
ctlr->pool = cpdma_desc_pool_create(ctlr->dev,
|
||||
ctlr->params.desc_mem_phys,
|
||||
ctlr->params.desc_mem_size,
|
||||
ctlr->params.desc_align);
|
||||
if (!ctlr->pool) {
|
||||
kfree(ctlr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WARN_ON(ctlr->num_chan > CPDMA_MAX_CHANNELS))
|
||||
ctlr->num_chan = CPDMA_MAX_CHANNELS;
|
||||
return ctlr;
|
||||
}
|
||||
|
||||
int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (ctlr->state != CPDMA_STATE_IDLE) {
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (ctlr->params.has_soft_reset) {
|
||||
unsigned long timeout = jiffies + HZ/10;
|
||||
|
||||
dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
|
||||
break;
|
||||
}
|
||||
WARN_ON(!time_before(jiffies, timeout));
|
||||
}
|
||||
|
||||
for (i = 0; i < ctlr->num_chan; i++) {
|
||||
__raw_writel(0, ctlr->params.txhdp + 4 * i);
|
||||
__raw_writel(0, ctlr->params.rxhdp + 4 * i);
|
||||
__raw_writel(0, ctlr->params.txcp + 4 * i);
|
||||
__raw_writel(0, ctlr->params.rxcp + 4 * i);
|
||||
}
|
||||
|
||||
dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
|
||||
dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
|
||||
|
||||
dma_reg_write(ctlr, CPDMA_TXCONTROL, 1);
|
||||
dma_reg_write(ctlr, CPDMA_RXCONTROL, 1);
|
||||
|
||||
ctlr->state = CPDMA_STATE_ACTIVE;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
|
||||
if (ctlr->channels[i])
|
||||
cpdma_chan_start(ctlr->channels[i]);
|
||||
}
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (ctlr->state != CPDMA_STATE_ACTIVE) {
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctlr->state = CPDMA_STATE_TEARDOWN;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
|
||||
if (ctlr->channels[i])
|
||||
cpdma_chan_stop(ctlr->channels[i]);
|
||||
}
|
||||
|
||||
dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
|
||||
dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
|
||||
|
||||
dma_reg_write(ctlr, CPDMA_TXCONTROL, 0);
|
||||
dma_reg_write(ctlr, CPDMA_RXCONTROL, 0);
|
||||
|
||||
ctlr->state = CPDMA_STATE_IDLE;
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr)
|
||||
{
|
||||
struct device *dev = ctlr->dev;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
dev_info(dev, "CPDMA: state: %s", cpdma_state_str[ctlr->state]);
|
||||
|
||||
dev_info(dev, "CPDMA: txidver: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXIDVER));
|
||||
dev_info(dev, "CPDMA: txcontrol: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXCONTROL));
|
||||
dev_info(dev, "CPDMA: txteardown: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXTEARDOWN));
|
||||
dev_info(dev, "CPDMA: rxidver: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXIDVER));
|
||||
dev_info(dev, "CPDMA: rxcontrol: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXCONTROL));
|
||||
dev_info(dev, "CPDMA: softreset: %x",
|
||||
dma_reg_read(ctlr, CPDMA_SOFTRESET));
|
||||
dev_info(dev, "CPDMA: rxteardown: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXTEARDOWN));
|
||||
dev_info(dev, "CPDMA: txintstatraw: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXINTSTATRAW));
|
||||
dev_info(dev, "CPDMA: txintstatmasked: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED));
|
||||
dev_info(dev, "CPDMA: txintmaskset: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXINTMASKSET));
|
||||
dev_info(dev, "CPDMA: txintmaskclear: %x",
|
||||
dma_reg_read(ctlr, CPDMA_TXINTMASKCLEAR));
|
||||
dev_info(dev, "CPDMA: macinvector: %x",
|
||||
dma_reg_read(ctlr, CPDMA_MACINVECTOR));
|
||||
dev_info(dev, "CPDMA: maceoivector: %x",
|
||||
dma_reg_read(ctlr, CPDMA_MACEOIVECTOR));
|
||||
dev_info(dev, "CPDMA: rxintstatraw: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXINTSTATRAW));
|
||||
dev_info(dev, "CPDMA: rxintstatmasked: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED));
|
||||
dev_info(dev, "CPDMA: rxintmaskset: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXINTMASKSET));
|
||||
dev_info(dev, "CPDMA: rxintmaskclear: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXINTMASKCLEAR));
|
||||
dev_info(dev, "CPDMA: dmaintstatraw: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMAINTSTATRAW));
|
||||
dev_info(dev, "CPDMA: dmaintstatmasked: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMAINTSTATMASKED));
|
||||
dev_info(dev, "CPDMA: dmaintmaskset: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMAINTMASKSET));
|
||||
dev_info(dev, "CPDMA: dmaintmaskclear: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMAINTMASKCLEAR));
|
||||
|
||||
if (!ctlr->params.has_ext_regs) {
|
||||
dev_info(dev, "CPDMA: dmacontrol: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMACONTROL));
|
||||
dev_info(dev, "CPDMA: dmastatus: %x",
|
||||
dma_reg_read(ctlr, CPDMA_DMASTATUS));
|
||||
dev_info(dev, "CPDMA: rxbuffofs: %x",
|
||||
dma_reg_read(ctlr, CPDMA_RXBUFFOFS));
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
|
||||
if (ctlr->channels[i])
|
||||
cpdma_chan_dump(ctlr->channels[i]);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0, i;
|
||||
|
||||
if (!ctlr)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (ctlr->state != CPDMA_STATE_IDLE)
|
||||
cpdma_ctlr_stop(ctlr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
|
||||
if (ctlr->channels[i])
|
||||
cpdma_chan_destroy(ctlr->channels[i]);
|
||||
}
|
||||
|
||||
cpdma_desc_pool_destroy(ctlr->pool);
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
kfree(ctlr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i, reg;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (ctlr->state != CPDMA_STATE_ACTIVE) {
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = enable ? CPDMA_DMAINTMASKSET : CPDMA_DMAINTMASKCLEAR;
|
||||
dma_reg_write(ctlr, reg, CPDMA_DMAINT_HOSTERR);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
|
||||
if (ctlr->channels[i])
|
||||
cpdma_chan_int_ctrl(ctlr->channels[i], enable);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
|
||||
{
|
||||
dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
|
||||
}
|
||||
|
||||
struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
|
||||
cpdma_handler_fn handler)
|
||||
{
|
||||
struct cpdma_chan *chan;
|
||||
int ret, offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;
|
||||
unsigned long flags;
|
||||
|
||||
if (__chan_linear(chan_num) >= ctlr->num_chan)
|
||||
return NULL;
|
||||
|
||||
ret = -ENOMEM;
|
||||
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
|
||||
if (!chan)
|
||||
goto err_chan_alloc;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
ret = -EBUSY;
|
||||
if (ctlr->channels[chan_num])
|
||||
goto err_chan_busy;
|
||||
|
||||
chan->ctlr = ctlr;
|
||||
chan->state = CPDMA_STATE_IDLE;
|
||||
chan->chan_num = chan_num;
|
||||
chan->handler = handler;
|
||||
|
||||
if (is_rx_chan(chan)) {
|
||||
chan->hdp = ctlr->params.rxhdp + offset;
|
||||
chan->cp = ctlr->params.rxcp + offset;
|
||||
chan->rxfree = ctlr->params.rxfree + offset;
|
||||
chan->int_set = CPDMA_RXINTMASKSET;
|
||||
chan->int_clear = CPDMA_RXINTMASKCLEAR;
|
||||
chan->td = CPDMA_RXTEARDOWN;
|
||||
chan->dir = DMA_FROM_DEVICE;
|
||||
} else {
|
||||
chan->hdp = ctlr->params.txhdp + offset;
|
||||
chan->cp = ctlr->params.txcp + offset;
|
||||
chan->int_set = CPDMA_TXINTMASKSET;
|
||||
chan->int_clear = CPDMA_TXINTMASKCLEAR;
|
||||
chan->td = CPDMA_TXTEARDOWN;
|
||||
chan->dir = DMA_TO_DEVICE;
|
||||
}
|
||||
chan->mask = BIT(chan_linear(chan));
|
||||
|
||||
spin_lock_init(&chan->lock);
|
||||
|
||||
ctlr->channels[chan_num] = chan;
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return chan;
|
||||
|
||||
err_chan_busy:
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
kfree(chan);
|
||||
err_chan_alloc:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int cpdma_chan_destroy(struct cpdma_chan *chan)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
unsigned long flags;
|
||||
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
if (chan->state != CPDMA_STATE_IDLE)
|
||||
cpdma_chan_stop(chan);
|
||||
ctlr->channels[chan->chan_num] = NULL;
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
kfree(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_chan_get_stats(struct cpdma_chan *chan,
|
||||
struct cpdma_chan_stats *stats)
|
||||
{
|
||||
unsigned long flags;
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
memcpy(stats, &chan->stats, sizeof(*stats));
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_chan_dump(struct cpdma_chan *chan)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct device *dev = chan->ctlr->dev;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
|
||||
dev_info(dev, "channel %d (%s %d) state %s",
|
||||
chan->chan_num, is_rx_chan(chan) ? "rx" : "tx",
|
||||
chan_linear(chan), cpdma_state_str[chan->state]);
|
||||
dev_info(dev, "\thdp: %x\n", chan_read(chan, hdp));
|
||||
dev_info(dev, "\tcp: %x\n", chan_read(chan, cp));
|
||||
if (chan->rxfree) {
|
||||
dev_info(dev, "\trxfree: %x\n",
|
||||
chan_read(chan, rxfree));
|
||||
}
|
||||
|
||||
dev_info(dev, "\tstats head_enqueue: %d\n",
|
||||
chan->stats.head_enqueue);
|
||||
dev_info(dev, "\tstats tail_enqueue: %d\n",
|
||||
chan->stats.tail_enqueue);
|
||||
dev_info(dev, "\tstats pad_enqueue: %d\n",
|
||||
chan->stats.pad_enqueue);
|
||||
dev_info(dev, "\tstats misqueued: %d\n",
|
||||
chan->stats.misqueued);
|
||||
dev_info(dev, "\tstats desc_alloc_fail: %d\n",
|
||||
chan->stats.desc_alloc_fail);
|
||||
dev_info(dev, "\tstats pad_alloc_fail: %d\n",
|
||||
chan->stats.pad_alloc_fail);
|
||||
dev_info(dev, "\tstats runt_receive_buff: %d\n",
|
||||
chan->stats.runt_receive_buff);
|
||||
dev_info(dev, "\tstats runt_transmit_buff: %d\n",
|
||||
chan->stats.runt_transmit_buff);
|
||||
dev_info(dev, "\tstats empty_dequeue: %d\n",
|
||||
chan->stats.empty_dequeue);
|
||||
dev_info(dev, "\tstats busy_dequeue: %d\n",
|
||||
chan->stats.busy_dequeue);
|
||||
dev_info(dev, "\tstats good_dequeue: %d\n",
|
||||
chan->stats.good_dequeue);
|
||||
dev_info(dev, "\tstats requeue: %d\n",
|
||||
chan->stats.requeue);
|
||||
dev_info(dev, "\tstats teardown_dequeue: %d\n",
|
||||
chan->stats.teardown_dequeue);
|
||||
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __cpdma_chan_submit(struct cpdma_chan *chan,
|
||||
struct cpdma_desc __iomem *desc)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc __iomem *prev = chan->tail;
|
||||
struct cpdma_desc_pool *pool = ctlr->pool;
|
||||
dma_addr_t desc_dma;
|
||||
u32 mode;
|
||||
|
||||
desc_dma = desc_phys(pool, desc);
|
||||
|
||||
/* simple case - idle channel */
|
||||
if (!chan->head) {
|
||||
chan->stats.head_enqueue++;
|
||||
chan->head = desc;
|
||||
chan->tail = desc;
|
||||
if (chan->state == CPDMA_STATE_ACTIVE)
|
||||
chan_write(chan, hdp, desc_dma);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first chain the descriptor at the tail of the list */
|
||||
desc_write(prev, hw_next, desc_dma);
|
||||
chan->tail = desc;
|
||||
chan->stats.tail_enqueue++;
|
||||
|
||||
/* next check if EOQ has been triggered already */
|
||||
mode = desc_read(prev, hw_mode);
|
||||
if (((mode & (CPDMA_DESC_EOQ | CPDMA_DESC_OWNER)) == CPDMA_DESC_EOQ) &&
|
||||
(chan->state == CPDMA_STATE_ACTIVE)) {
|
||||
desc_write(prev, hw_mode, mode & ~CPDMA_DESC_EOQ);
|
||||
chan_write(chan, hdp, desc_dma);
|
||||
chan->stats.misqueued++;
|
||||
}
|
||||
}
|
||||
|
||||
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
|
||||
int len, gfp_t gfp_mask)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc __iomem *desc;
|
||||
dma_addr_t buffer;
|
||||
unsigned long flags;
|
||||
u32 mode;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
|
||||
if (chan->state == CPDMA_STATE_TEARDOWN) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_ret;
|
||||
}
|
||||
|
||||
desc = cpdma_desc_alloc(ctlr->pool, 1);
|
||||
if (!desc) {
|
||||
chan->stats.desc_alloc_fail++;
|
||||
ret = -ENOMEM;
|
||||
goto unlock_ret;
|
||||
}
|
||||
|
||||
if (len < ctlr->params.min_packet_size) {
|
||||
len = ctlr->params.min_packet_size;
|
||||
chan->stats.runt_transmit_buff++;
|
||||
}
|
||||
|
||||
buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
|
||||
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
|
||||
|
||||
desc_write(desc, hw_next, 0);
|
||||
desc_write(desc, hw_buffer, buffer);
|
||||
desc_write(desc, hw_len, len);
|
||||
desc_write(desc, hw_mode, mode | len);
|
||||
desc_write(desc, sw_token, token);
|
||||
desc_write(desc, sw_buffer, buffer);
|
||||
desc_write(desc, sw_len, len);
|
||||
|
||||
__cpdma_chan_submit(chan, desc);
|
||||
|
||||
if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree)
|
||||
chan_write(chan, rxfree, 1);
|
||||
|
||||
chan->count++;
|
||||
|
||||
unlock_ret:
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __cpdma_chan_free(struct cpdma_chan *chan,
|
||||
struct cpdma_desc __iomem *desc,
|
||||
int outlen, int status)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc_pool *pool = ctlr->pool;
|
||||
dma_addr_t buff_dma;
|
||||
int origlen;
|
||||
void *token;
|
||||
|
||||
token = (void *)desc_read(desc, sw_token);
|
||||
buff_dma = desc_read(desc, sw_buffer);
|
||||
origlen = desc_read(desc, sw_len);
|
||||
|
||||
dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
|
||||
cpdma_desc_free(pool, desc, 1);
|
||||
(*chan->handler)(token, outlen, status);
|
||||
}
|
||||
|
||||
static int __cpdma_chan_process(struct cpdma_chan *chan)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc __iomem *desc;
|
||||
int status, outlen;
|
||||
struct cpdma_desc_pool *pool = ctlr->pool;
|
||||
dma_addr_t desc_dma;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
|
||||
desc = chan->head;
|
||||
if (!desc) {
|
||||
chan->stats.empty_dequeue++;
|
||||
status = -ENOENT;
|
||||
goto unlock_ret;
|
||||
}
|
||||
desc_dma = desc_phys(pool, desc);
|
||||
|
||||
status = __raw_readl(&desc->hw_mode);
|
||||
outlen = status & 0x7ff;
|
||||
if (status & CPDMA_DESC_OWNER) {
|
||||
chan->stats.busy_dequeue++;
|
||||
status = -EBUSY;
|
||||
goto unlock_ret;
|
||||
}
|
||||
status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
|
||||
|
||||
chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
|
||||
chan_write(chan, cp, desc_dma);
|
||||
chan->count--;
|
||||
chan->stats.good_dequeue++;
|
||||
|
||||
if (status & CPDMA_DESC_EOQ) {
|
||||
chan->stats.requeue++;
|
||||
chan_write(chan, hdp, desc_phys(pool, chan->head));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
__cpdma_chan_free(chan, desc, outlen, status);
|
||||
return status;
|
||||
|
||||
unlock_ret:
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
int cpdma_chan_process(struct cpdma_chan *chan, int quota)
|
||||
{
|
||||
int used = 0, ret = 0;
|
||||
|
||||
if (chan->state != CPDMA_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
while (used < quota) {
|
||||
ret = __cpdma_chan_process(chan);
|
||||
if (ret < 0)
|
||||
break;
|
||||
used++;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
int cpdma_chan_start(struct cpdma_chan *chan)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc_pool *pool = ctlr->pool;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
if (chan->state != CPDMA_STATE_IDLE) {
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (ctlr->state != CPDMA_STATE_ACTIVE) {
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
dma_reg_write(ctlr, chan->int_set, chan->mask);
|
||||
chan->state = CPDMA_STATE_ACTIVE;
|
||||
if (chan->head) {
|
||||
chan_write(chan, hdp, desc_phys(pool, chan->head));
|
||||
if (chan->rxfree)
|
||||
chan_write(chan, rxfree, chan->count);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_chan_stop(struct cpdma_chan *chan)
|
||||
{
|
||||
struct cpdma_ctlr *ctlr = chan->ctlr;
|
||||
struct cpdma_desc_pool *pool = ctlr->pool;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
unsigned long timeout;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
if (chan->state != CPDMA_STATE_ACTIVE) {
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chan->state = CPDMA_STATE_TEARDOWN;
|
||||
dma_reg_write(ctlr, chan->int_clear, chan->mask);
|
||||
|
||||
/* trigger teardown */
|
||||
dma_reg_write(ctlr, chan->td, chan->chan_num);
|
||||
|
||||
/* wait for teardown complete */
|
||||
timeout = jiffies + HZ/10; /* 100 msec */
|
||||
while (time_before(jiffies, timeout)) {
|
||||
u32 cp = chan_read(chan, cp);
|
||||
if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
WARN_ON(!time_before(jiffies, timeout));
|
||||
chan_write(chan, cp, CPDMA_TEARDOWN_VALUE);
|
||||
|
||||
/* handle completed packets */
|
||||
do {
|
||||
ret = __cpdma_chan_process(chan);
|
||||
if (ret < 0)
|
||||
break;
|
||||
} while ((ret & CPDMA_DESC_TD_COMPLETE) == 0);
|
||||
|
||||
/* remaining packets haven't been tx/rx'ed, clean them up */
|
||||
while (chan->head) {
|
||||
struct cpdma_desc __iomem *desc = chan->head;
|
||||
dma_addr_t next_dma;
|
||||
|
||||
next_dma = desc_read(desc, hw_next);
|
||||
chan->head = desc_from_phys(pool, next_dma);
|
||||
chan->stats.teardown_dequeue++;
|
||||
|
||||
/* issue callback without locks held */
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
__cpdma_chan_free(chan, desc, 0, -ENOSYS);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
}
|
||||
|
||||
chan->state = CPDMA_STATE_IDLE;
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
if (chan->state != CPDMA_STATE_ACTIVE) {
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dma_reg_write(chan->ctlr, enable ? chan->int_set : chan->int_clear,
|
||||
chan->mask);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cpdma_control_info {
|
||||
u32 reg;
|
||||
u32 shift, mask;
|
||||
int access;
|
||||
#define ACCESS_RO BIT(0)
|
||||
#define ACCESS_WO BIT(1)
|
||||
#define ACCESS_RW (ACCESS_RO | ACCESS_WO)
|
||||
};
|
||||
|
||||
struct cpdma_control_info controls[] = {
|
||||
[CPDMA_CMD_IDLE] = {CPDMA_DMACONTROL, 3, 1, ACCESS_WO},
|
||||
[CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL, 4, 1, ACCESS_RW},
|
||||
[CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL, 2, 1, ACCESS_RW},
|
||||
[CPDMA_RX_OWNERSHIP_FLIP] = {CPDMA_DMACONTROL, 1, 1, ACCESS_RW},
|
||||
[CPDMA_TX_PRIO_FIXED] = {CPDMA_DMACONTROL, 0, 1, ACCESS_RW},
|
||||
[CPDMA_STAT_IDLE] = {CPDMA_DMASTATUS, 31, 1, ACCESS_RO},
|
||||
[CPDMA_STAT_TX_ERR_CODE] = {CPDMA_DMASTATUS, 20, 0xf, ACCESS_RW},
|
||||
[CPDMA_STAT_TX_ERR_CHAN] = {CPDMA_DMASTATUS, 16, 0x7, ACCESS_RW},
|
||||
[CPDMA_STAT_RX_ERR_CODE] = {CPDMA_DMASTATUS, 12, 0xf, ACCESS_RW},
|
||||
[CPDMA_STAT_RX_ERR_CHAN] = {CPDMA_DMASTATUS, 8, 0x7, ACCESS_RW},
|
||||
[CPDMA_RX_BUFFER_OFFSET] = {CPDMA_RXBUFFOFS, 0, 0xffff, ACCESS_RW},
|
||||
};
|
||||
|
||||
int cpdma_control_get(struct cpdma_ctlr *ctlr, int control)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct cpdma_control_info *info = &controls[control];
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
ret = -ENOTSUPP;
|
||||
if (!ctlr->params.has_ext_regs)
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (ctlr->state != CPDMA_STATE_ACTIVE)
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -ENOENT;
|
||||
if (control < 0 || control >= ARRAY_SIZE(controls))
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -EPERM;
|
||||
if ((info->access & ACCESS_RO) != ACCESS_RO)
|
||||
goto unlock_ret;
|
||||
|
||||
ret = (dma_reg_read(ctlr, info->reg) >> info->shift) & info->mask;
|
||||
|
||||
unlock_ret:
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct cpdma_control_info *info = &controls[control];
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
ret = -ENOTSUPP;
|
||||
if (!ctlr->params.has_ext_regs)
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (ctlr->state != CPDMA_STATE_ACTIVE)
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -ENOENT;
|
||||
if (control < 0 || control >= ARRAY_SIZE(controls))
|
||||
goto unlock_ret;
|
||||
|
||||
ret = -EPERM;
|
||||
if ((info->access & ACCESS_WO) != ACCESS_WO)
|
||||
goto unlock_ret;
|
||||
|
||||
val = dma_reg_read(ctlr, info->reg);
|
||||
val &= ~(info->mask << info->shift);
|
||||
val |= (value & info->mask) << info->shift;
|
||||
dma_reg_write(ctlr, info->reg, val);
|
||||
ret = 0;
|
||||
|
||||
unlock_ret:
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Texas Instruments CPDMA Driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef __DAVINCI_CPDMA_H__
|
||||
#define __DAVINCI_CPDMA_H__
|
||||
|
||||
#define CPDMA_MAX_CHANNELS BITS_PER_LONG
|
||||
|
||||
#define tx_chan_num(chan) (chan)
|
||||
#define rx_chan_num(chan) ((chan) + CPDMA_MAX_CHANNELS)
|
||||
#define is_rx_chan(chan) ((chan)->chan_num >= CPDMA_MAX_CHANNELS)
|
||||
#define is_tx_chan(chan) (!is_rx_chan(chan))
|
||||
#define __chan_linear(chan_num) ((chan_num) & (CPDMA_MAX_CHANNELS - 1))
|
||||
#define chan_linear(chan) __chan_linear((chan)->chan_num)
|
||||
|
||||
struct cpdma_params {
|
||||
struct device *dev;
|
||||
void __iomem *dmaregs;
|
||||
void __iomem *txhdp, *rxhdp, *txcp, *rxcp;
|
||||
void __iomem *rxthresh, *rxfree;
|
||||
int num_chan;
|
||||
bool has_soft_reset;
|
||||
int min_packet_size;
|
||||
u32 desc_mem_phys;
|
||||
int desc_mem_size;
|
||||
int desc_align;
|
||||
|
||||
/*
|
||||
* Some instances of embedded cpdma controllers have extra control and
|
||||
* status registers. The following flag enables access to these
|
||||
* "extended" registers.
|
||||
*/
|
||||
bool has_ext_regs;
|
||||
};
|
||||
|
||||
struct cpdma_chan_stats {
|
||||
u32 head_enqueue;
|
||||
u32 tail_enqueue;
|
||||
u32 pad_enqueue;
|
||||
u32 misqueued;
|
||||
u32 desc_alloc_fail;
|
||||
u32 pad_alloc_fail;
|
||||
u32 runt_receive_buff;
|
||||
u32 runt_transmit_buff;
|
||||
u32 empty_dequeue;
|
||||
u32 busy_dequeue;
|
||||
u32 good_dequeue;
|
||||
u32 requeue;
|
||||
u32 teardown_dequeue;
|
||||
};
|
||||
|
||||
struct cpdma_ctlr;
|
||||
struct cpdma_chan;
|
||||
|
||||
typedef void (*cpdma_handler_fn)(void *token, int len, int status);
|
||||
|
||||
struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params);
|
||||
int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr);
|
||||
int cpdma_ctlr_start(struct cpdma_ctlr *ctlr);
|
||||
int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr);
|
||||
int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr);
|
||||
|
||||
struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
|
||||
cpdma_handler_fn handler);
|
||||
int cpdma_chan_destroy(struct cpdma_chan *chan);
|
||||
int cpdma_chan_start(struct cpdma_chan *chan);
|
||||
int cpdma_chan_stop(struct cpdma_chan *chan);
|
||||
int cpdma_chan_dump(struct cpdma_chan *chan);
|
||||
|
||||
int cpdma_chan_get_stats(struct cpdma_chan *chan,
|
||||
struct cpdma_chan_stats *stats);
|
||||
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
|
||||
int len, gfp_t gfp_mask);
|
||||
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
|
||||
|
||||
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
|
||||
void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
|
||||
int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
|
||||
|
||||
enum cpdma_control {
|
||||
CPDMA_CMD_IDLE, /* write-only */
|
||||
CPDMA_COPY_ERROR_FRAMES, /* read-write */
|
||||
CPDMA_RX_OFF_LEN_UPDATE, /* read-write */
|
||||
CPDMA_RX_OWNERSHIP_FLIP, /* read-write */
|
||||
CPDMA_TX_PRIO_FIXED, /* read-write */
|
||||
CPDMA_STAT_IDLE, /* read-only */
|
||||
CPDMA_STAT_TX_ERR_CHAN, /* read-only */
|
||||
CPDMA_STAT_TX_ERR_CODE, /* read-only */
|
||||
CPDMA_STAT_RX_ERR_CHAN, /* read-only */
|
||||
CPDMA_STAT_RX_ERR_CODE, /* read-only */
|
||||
CPDMA_RX_BUFFER_OFFSET, /* read-write */
|
||||
};
|
||||
|
||||
int cpdma_control_get(struct cpdma_ctlr *ctlr, int control);
|
||||
int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value);
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* DaVinci MDIO Module driver
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
* Shamelessly ripped out of davinci_emac.c, original copyrights follow:
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments.
|
||||
*
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/davinci_emac.h>
|
||||
|
||||
/*
|
||||
* This timeout definition is a worst-case ultra defensive measure against
|
||||
* unexpected controller lock ups. Ideally, we should never ever hit this
|
||||
* scenario in practice.
|
||||
*/
|
||||
#define MDIO_TIMEOUT 100 /* msecs */
|
||||
|
||||
#define PHY_REG_MASK 0x1f
|
||||
#define PHY_ID_MASK 0x1f
|
||||
|
||||
#define DEF_OUT_FREQ 2200000 /* 2.2 MHz */
|
||||
|
||||
struct davinci_mdio_regs {
|
||||
u32 version;
|
||||
u32 control;
|
||||
#define CONTROL_IDLE BIT(31)
|
||||
#define CONTROL_ENABLE BIT(30)
|
||||
#define CONTROL_MAX_DIV (0xff)
|
||||
|
||||
u32 alive;
|
||||
u32 link;
|
||||
u32 linkintraw;
|
||||
u32 linkintmasked;
|
||||
u32 __reserved_0[2];
|
||||
u32 userintraw;
|
||||
u32 userintmasked;
|
||||
u32 userintmaskset;
|
||||
u32 userintmaskclr;
|
||||
u32 __reserved_1[20];
|
||||
|
||||
struct {
|
||||
u32 access;
|
||||
#define USERACCESS_GO BIT(31)
|
||||
#define USERACCESS_WRITE BIT(30)
|
||||
#define USERACCESS_ACK BIT(29)
|
||||
#define USERACCESS_READ (0)
|
||||
#define USERACCESS_DATA (0xffff)
|
||||
|
||||
u32 physel;
|
||||
} user[0];
|
||||
};
|
||||
|
||||
struct mdio_platform_data default_pdata = {
|
||||
.bus_freq = DEF_OUT_FREQ,
|
||||
};
|
||||
|
||||
struct davinci_mdio_data {
|
||||
struct mdio_platform_data pdata;
|
||||
struct davinci_mdio_regs __iomem *regs;
|
||||
spinlock_t lock;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
struct mii_bus *bus;
|
||||
bool suspended;
|
||||
unsigned long access_time; /* jiffies */
|
||||
};
|
||||
|
||||
static void __davinci_mdio_reset(struct davinci_mdio_data *data)
|
||||
{
|
||||
u32 mdio_in, div, mdio_out_khz, access_time;
|
||||
|
||||
mdio_in = clk_get_rate(data->clk);
|
||||
div = (mdio_in / data->pdata.bus_freq) - 1;
|
||||
if (div > CONTROL_MAX_DIV)
|
||||
div = CONTROL_MAX_DIV;
|
||||
|
||||
/* set enable and clock divider */
|
||||
__raw_writel(div | CONTROL_ENABLE, &data->regs->control);
|
||||
|
||||
/*
|
||||
* One mdio transaction consists of:
|
||||
* 32 bits of preamble
|
||||
* 32 bits of transferred data
|
||||
* 24 bits of bus yield (not needed unless shared?)
|
||||
*/
|
||||
mdio_out_khz = mdio_in / (1000 * (div + 1));
|
||||
access_time = (88 * 1000) / mdio_out_khz;
|
||||
|
||||
/*
|
||||
* In the worst case, we could be kicking off a user-access immediately
|
||||
* after the mdio bus scan state-machine triggered its own read. If
|
||||
* so, our request could get deferred by one access cycle. We
|
||||
* defensively allow for 4 access cycles.
|
||||
*/
|
||||
data->access_time = usecs_to_jiffies(access_time * 4);
|
||||
if (!data->access_time)
|
||||
data->access_time = 1;
|
||||
}
|
||||
|
||||
static int davinci_mdio_reset(struct mii_bus *bus)
|
||||
{
|
||||
struct davinci_mdio_data *data = bus->priv;
|
||||
u32 phy_mask, ver;
|
||||
|
||||
__davinci_mdio_reset(data);
|
||||
|
||||
/* wait for scan logic to settle */
|
||||
msleep(PHY_MAX_ADDR * data->access_time);
|
||||
|
||||
/* dump hardware version info */
|
||||
ver = __raw_readl(&data->regs->version);
|
||||
dev_info(data->dev, "davinci mdio revision %d.%d\n",
|
||||
(ver >> 8) & 0xff, ver & 0xff);
|
||||
|
||||
/* get phy mask from the alive register */
|
||||
phy_mask = __raw_readl(&data->regs->alive);
|
||||
if (phy_mask) {
|
||||
/* restrict mdio bus to live phys only */
|
||||
dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
|
||||
phy_mask = ~phy_mask;
|
||||
} else {
|
||||
/* desperately scan all phys */
|
||||
dev_warn(data->dev, "no live phy, scanning all\n");
|
||||
phy_mask = 0;
|
||||
}
|
||||
data->bus->phy_mask = phy_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait until hardware is ready for another user access */
|
||||
static inline int wait_for_user_access(struct davinci_mdio_data *data)
|
||||
{
|
||||
struct davinci_mdio_regs __iomem *regs = data->regs;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
|
||||
u32 reg;
|
||||
|
||||
while (time_after(timeout, jiffies)) {
|
||||
reg = __raw_readl(®s->user[0].access);
|
||||
if ((reg & USERACCESS_GO) == 0)
|
||||
return 0;
|
||||
|
||||
reg = __raw_readl(®s->control);
|
||||
if ((reg & CONTROL_IDLE) == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* An emac soft_reset may have clobbered the mdio controller's
|
||||
* state machine. We need to reset and retry the current
|
||||
* operation
|
||||
*/
|
||||
dev_warn(data->dev, "resetting idled controller\n");
|
||||
__davinci_mdio_reset(data);
|
||||
return -EAGAIN;
|
||||
}
|
||||
dev_err(data->dev, "timed out waiting for user access\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* wait until hardware state machine is idle */
|
||||
static inline int wait_for_idle(struct davinci_mdio_data *data)
|
||||
{
|
||||
struct davinci_mdio_regs __iomem *regs = data->regs;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
|
||||
|
||||
while (time_after(timeout, jiffies)) {
|
||||
if (__raw_readl(®s->control) & CONTROL_IDLE)
|
||||
return 0;
|
||||
}
|
||||
dev_err(data->dev, "timed out waiting for idle\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int davinci_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
|
||||
{
|
||||
struct davinci_mdio_data *data = bus->priv;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&data->lock);
|
||||
|
||||
if (data->suspended) {
|
||||
spin_unlock(&data->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
|
||||
(phy_id << 16));
|
||||
|
||||
while (1) {
|
||||
ret = wait_for_user_access(data);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
__raw_writel(reg, &data->regs->user[0].access);
|
||||
|
||||
ret = wait_for_user_access(data);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
reg = __raw_readl(&data->regs->user[0].access);
|
||||
ret = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
|
||||
int phy_reg, u16 phy_data)
|
||||
{
|
||||
struct davinci_mdio_data *data = bus->priv;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&data->lock);
|
||||
|
||||
if (data->suspended) {
|
||||
spin_unlock(&data->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
|
||||
(phy_id << 16) | (phy_data & USERACCESS_DATA));
|
||||
|
||||
while (1) {
|
||||
ret = wait_for_user_access(data);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
__raw_writel(reg, &data->regs->user[0].access);
|
||||
|
||||
ret = wait_for_user_access(data);
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit davinci_mdio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mdio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_mdio_data *data;
|
||||
struct resource *res;
|
||||
struct phy_device *phy;
|
||||
int ret, addr;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(dev, "failed to alloc device data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->pdata = pdata ? (*pdata) : default_pdata;
|
||||
|
||||
data->bus = mdiobus_alloc();
|
||||
if (!data->bus) {
|
||||
dev_err(dev, "failed to alloc mii bus\n");
|
||||
ret = -ENOMEM;
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
data->bus->name = dev_name(dev);
|
||||
data->bus->read = davinci_mdio_read,
|
||||
data->bus->write = davinci_mdio_write,
|
||||
data->bus->reset = davinci_mdio_reset,
|
||||
data->bus->parent = dev;
|
||||
data->bus->priv = data;
|
||||
snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
|
||||
|
||||
data->clk = clk_get(dev, NULL);
|
||||
if (IS_ERR(data->clk)) {
|
||||
data->clk = NULL;
|
||||
dev_err(dev, "failed to get device clock\n");
|
||||
ret = PTR_ERR(data->clk);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
clk_enable(data->clk);
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
data->dev = dev;
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "could not find register map resource\n");
|
||||
ret = -ENOENT;
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
res = devm_request_mem_region(dev, res->start, resource_size(res),
|
||||
dev_name(dev));
|
||||
if (!res) {
|
||||
dev_err(dev, "could not allocate register map resource\n");
|
||||
ret = -ENXIO;
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||
if (!data->regs) {
|
||||
dev_err(dev, "could not map mdio registers\n");
|
||||
ret = -ENOMEM;
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
/* register the mii bus */
|
||||
ret = mdiobus_register(data->bus);
|
||||
if (ret)
|
||||
goto bail_out;
|
||||
|
||||
/* scan and dump the bus */
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
|
||||
phy = data->bus->phy_map[addr];
|
||||
if (phy) {
|
||||
dev_info(dev, "phy[%d]: device %s, driver %s\n",
|
||||
phy->addr, dev_name(&phy->dev),
|
||||
phy->drv ? phy->drv->name : "unknown");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail_out:
|
||||
if (data->bus)
|
||||
mdiobus_free(data->bus);
|
||||
|
||||
if (data->clk) {
|
||||
clk_disable(data->clk);
|
||||
clk_put(data->clk);
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit davinci_mdio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (data->bus)
|
||||
mdiobus_free(data->bus);
|
||||
|
||||
if (data->clk) {
|
||||
clk_disable(data->clk);
|
||||
clk_put(data->clk);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, NULL);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_mdio_suspend(struct device *dev)
|
||||
{
|
||||
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
||||
u32 ctrl;
|
||||
|
||||
spin_lock(&data->lock);
|
||||
|
||||
/* shutdown the scan state machine */
|
||||
ctrl = __raw_readl(&data->regs->control);
|
||||
ctrl &= ~CONTROL_ENABLE;
|
||||
__raw_writel(ctrl, &data->regs->control);
|
||||
wait_for_idle(data);
|
||||
|
||||
if (data->clk)
|
||||
clk_disable(data->clk);
|
||||
|
||||
data->suspended = true;
|
||||
spin_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_mdio_resume(struct device *dev)
|
||||
{
|
||||
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
||||
u32 ctrl;
|
||||
|
||||
spin_lock(&data->lock);
|
||||
if (data->clk)
|
||||
clk_enable(data->clk);
|
||||
|
||||
/* restart the scan state machine */
|
||||
ctrl = __raw_readl(&data->regs->control);
|
||||
ctrl |= CONTROL_ENABLE;
|
||||
__raw_writel(ctrl, &data->regs->control);
|
||||
|
||||
data->suspended = false;
|
||||
spin_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops davinci_mdio_pm_ops = {
|
||||
.suspend = davinci_mdio_suspend,
|
||||
.resume = davinci_mdio_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver davinci_mdio_driver = {
|
||||
.driver = {
|
||||
.name = "davinci_mdio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &davinci_mdio_pm_ops,
|
||||
},
|
||||
.probe = davinci_mdio_probe,
|
||||
.remove = __devexit_p(davinci_mdio_remove),
|
||||
};
|
||||
|
||||
static int __init davinci_mdio_init(void)
|
||||
{
|
||||
return platform_driver_register(&davinci_mdio_driver);
|
||||
}
|
||||
device_initcall(davinci_mdio_init);
|
||||
|
||||
static void __exit davinci_mdio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&davinci_mdio_driver);
|
||||
}
|
||||
module_exit(davinci_mdio_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("DaVinci MDIO driver");
|
|
@ -14,16 +14,26 @@
|
|||
#include <linux/if_ether.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
struct mdio_platform_data {
|
||||
unsigned long bus_freq;
|
||||
};
|
||||
|
||||
struct emac_platform_data {
|
||||
char mac_addr[ETH_ALEN];
|
||||
u32 ctrl_reg_offset;
|
||||
u32 ctrl_mod_reg_offset;
|
||||
u32 ctrl_ram_offset;
|
||||
u32 hw_ram_addr;
|
||||
u32 mdio_reg_offset;
|
||||
u32 ctrl_ram_size;
|
||||
u32 phy_mask;
|
||||
u32 mdio_max_freq;
|
||||
|
||||
/*
|
||||
* phy_id can be one of the following:
|
||||
* - NULL : use the first phy on the bus,
|
||||
* - "" : force to 100/full, no mdio control
|
||||
* - "<bus>:<addr>" : use the specified bus and phy
|
||||
*/
|
||||
const char *phy_id;
|
||||
|
||||
u8 rmii_en;
|
||||
u8 version;
|
||||
void (*interrupt_enable) (void);
|
||||
|
|
Загрузка…
Ссылка в новой задаче