mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
arm-soc: device tree conversions, part 1
The spear3xx, lpc32xx, shmobile and mmp platforms are joining the game of booting using device trees, which is a great step forward for them. at91 and spear have pretty much completed this process with a huge amount of work being put into at91. The other platforms are continuing the process. We finally start to see the payback on this investment, as new machines are getting supported purely by adding a .dts source file that can be completely independent of the kernel source. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPueqRAAoJEIwa5zzehBx3AYkP/ibDGGd0qp1gxnxPYowliXcp lrWP8KB2PVcX/041jwpvsWeHzWT+Gm39ryBfz2L3pq/RiuU0jPPwChKgy1iglE8X 6Rq6sPWkXoDRtyeCuoiaxf1AYuzzAVdzZ0HlPO93tSKgo5eeyZRC5OeebAnrLDCE SDi8gZx2mm9+j2Dz46gq8QluyswMMbke3fHHHaHUlcP9fKIvFWvEfsn5j+YQ9bSw DrSIqGOzv6Emn7F6yhFQqxmk86KLnaXDVpAWgjVDhzaPv0rcTzloN6D2Ie2e5Vev BiRM1zvWn2d9kDk7gpm0t67nguYxsCBl1GNCP1brrncGwt15S10JimYlRhYW+B7u qgJqMPko3OnONvyl6e8qgIa2M5N4K/mo1i/jfOwFw3+KfUjXqLeio53Ysr4a6tsM Ev3bEsofNJKA0dlMcVzr7ntL087B6Y8mY3oJsVZji5M0KVfx1Jfn+X1W+l/2KD1H XWhJrCGa1HlbtSnrD+E91VHGC3M4sEXbbTljMAjHImlU9dGXmmbRMNsqNwkF6qFj EO2HnFvdN1oK+zEmeAttR1JHxfMdPFnTfmpUf3AiVSjGO//Wltelqx8ibA2Smn7S xXmzqX/HMhIOYCh81FdvzsK4qRYU5QyOsEJB4G0UjBZ66M1A3T/+vPpWuKsw5bUb qbnxaaXNsaZjWbbSSrZ4 =7DYv -----END PGP SIGNATURE----- Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull device tree conversions for arm-soc, part 1, from Olof Johansson: "The spear3xx, lpc32xx, shmobile and mmp platforms are joining the game of booting using device trees, which is a great step forward for them. at91 and spear have pretty much completed this process with a huge amount of work being put into at91. The other platforms are continuing the process. We finally start to see the payback on this investment, as new machines are getting supported purely by adding a .dts source file that can be completely independent of the kernel source." Fix up trivial conflict in arch/arm/Kconfig * tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (83 commits) ARM: at91: Add ADC driver to at91sam9260/at91sam9g20 dtsi files arm/dts: omap4-panda: Add LEDs support arm/dts: omap4-sdp: Add LEDs support arm/dts: twl4030: Add twl4030-gpio node OMAP4: devices: Do not create mcpdm device if the dtb has been provided OMAP4: devices: Do not create dmic device if the dtb has been provided Documentation: update docs for mmp dt ARM: dts: refresh dts file for arch mmp ARM: mmp: support pxa910 with device tree ARM: mmp: support mmp2 with device tree gpio: pxa: parse gpio from DTS file ARM: mmp: support DT in timer ARM: mmp: support DT in irq ARM: mmp: append CONFIG_MACH_MMP2_DT ARM: mmp: fix build issue on mmp with device tree ARM: ux500: Enable PRCMU Timer 4 (clocksource) for Device Tree ARM: ux500: Disable SMSC911x platform code registration when DT is enabled ARM: ux500: Fork cpu-db8500 platform_devs for sequential DT enablement ARM: ux500: Do not attempt to register non-existent i2c devices on Snowball ARM: SPEAr3xx: Correct keyboard data passed from DT ...
This commit is contained in:
commit
b324c67d48
138 changed files with 7736 additions and 2906 deletions
|
|
@ -23,16 +23,61 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_i2c.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/i2c.h>
|
||||
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
|
||||
#define I2C_PNX_SPEED_KHZ_DEFAULT 100
|
||||
#define I2C_PNX_REGION_SIZE 0x100
|
||||
|
||||
#define I2C_PNX_TIMEOUT 10 /* msec */
|
||||
#define I2C_PNX_SPEED_KHZ 100
|
||||
#define I2C_PNX_REGION_SIZE 0x100
|
||||
enum {
|
||||
mstatus_tdi = 0x00000001,
|
||||
mstatus_afi = 0x00000002,
|
||||
mstatus_nai = 0x00000004,
|
||||
mstatus_drmi = 0x00000008,
|
||||
mstatus_active = 0x00000020,
|
||||
mstatus_scl = 0x00000040,
|
||||
mstatus_sda = 0x00000080,
|
||||
mstatus_rff = 0x00000100,
|
||||
mstatus_rfe = 0x00000200,
|
||||
mstatus_tff = 0x00000400,
|
||||
mstatus_tfe = 0x00000800,
|
||||
};
|
||||
|
||||
static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
|
||||
enum {
|
||||
mcntrl_tdie = 0x00000001,
|
||||
mcntrl_afie = 0x00000002,
|
||||
mcntrl_naie = 0x00000004,
|
||||
mcntrl_drmie = 0x00000008,
|
||||
mcntrl_daie = 0x00000020,
|
||||
mcntrl_rffie = 0x00000040,
|
||||
mcntrl_tffie = 0x00000080,
|
||||
mcntrl_reset = 0x00000100,
|
||||
mcntrl_cdbmode = 0x00000400,
|
||||
};
|
||||
|
||||
enum {
|
||||
rw_bit = 1 << 0,
|
||||
start_bit = 1 << 8,
|
||||
stop_bit = 1 << 9,
|
||||
};
|
||||
|
||||
#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
|
||||
#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
|
||||
#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
|
||||
#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
|
||||
#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
|
||||
#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
|
||||
#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
|
||||
#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
|
||||
#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
|
||||
#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
|
||||
#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
|
||||
#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
|
||||
#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
|
||||
|
||||
static inline int wait_timeout(struct i2c_pnx_algo_data *data)
|
||||
{
|
||||
long timeout = data->timeout;
|
||||
while (timeout > 0 &&
|
||||
(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
|
||||
mdelay(1);
|
||||
|
|
@ -41,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
|
|||
return (timeout <= 0);
|
||||
}
|
||||
|
||||
static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
|
||||
static inline int wait_reset(struct i2c_pnx_algo_data *data)
|
||||
{
|
||||
long timeout = data->timeout;
|
||||
while (timeout > 0 &&
|
||||
(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
|
||||
mdelay(1);
|
||||
|
|
@ -54,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
|
|||
static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
|
||||
{
|
||||
struct timer_list *timer = &alg_data->mif.timer;
|
||||
unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
|
||||
unsigned long expires = msecs_to_jiffies(alg_data->timeout);
|
||||
|
||||
if (expires <= 1)
|
||||
expires = 2;
|
||||
|
|
@ -92,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr,
|
|||
}
|
||||
|
||||
/* First, make sure bus is idle */
|
||||
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
|
||||
if (wait_timeout(alg_data)) {
|
||||
/* Somebody else is monopolizing the bus */
|
||||
dev_err(&alg_data->adapter.dev,
|
||||
"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
|
||||
|
|
@ -185,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
|
|||
if (alg_data->mif.len == 0) {
|
||||
if (alg_data->last) {
|
||||
/* Wait until the STOP is seen. */
|
||||
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
|
||||
if (wait_timeout(alg_data))
|
||||
dev_err(&alg_data->adapter.dev,
|
||||
"The bus is still active after timeout\n");
|
||||
}
|
||||
|
|
@ -283,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
|
|||
if (alg_data->mif.len == 0) {
|
||||
if (alg_data->last)
|
||||
/* Wait until the STOP is seen. */
|
||||
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
|
||||
if (wait_timeout(alg_data))
|
||||
dev_err(&alg_data->adapter.dev,
|
||||
"The bus is still active after timeout\n");
|
||||
|
||||
|
|
@ -399,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data)
|
|||
|
||||
ctl |= mcntrl_reset;
|
||||
iowrite32(ctl, I2C_REG_CTL(alg_data));
|
||||
wait_reset(I2C_PNX_TIMEOUT, alg_data);
|
||||
wait_reset(alg_data);
|
||||
alg_data->mif.ret = -EIO;
|
||||
complete(&alg_data->mif.complete);
|
||||
}
|
||||
|
|
@ -414,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
|
|||
alg_data->adapter.name);
|
||||
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
|
||||
I2C_REG_CTL(alg_data));
|
||||
wait_reset(I2C_PNX_TIMEOUT, alg_data);
|
||||
wait_reset(alg_data);
|
||||
} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
|
||||
/* If there is data in the fifo's after transfer,
|
||||
* flush fifo's by reset.
|
||||
*/
|
||||
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
|
||||
I2C_REG_CTL(alg_data));
|
||||
wait_reset(I2C_PNX_TIMEOUT, alg_data);
|
||||
wait_reset(alg_data);
|
||||
} else if (stat & mstatus_nai) {
|
||||
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
|
||||
I2C_REG_CTL(alg_data));
|
||||
wait_reset(I2C_PNX_TIMEOUT, alg_data);
|
||||
wait_reset(alg_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,14 +614,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
int ret = 0;
|
||||
struct i2c_pnx_algo_data *alg_data;
|
||||
unsigned long freq;
|
||||
struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
|
||||
|
||||
if (!i2c_pnx || !i2c_pnx->name) {
|
||||
dev_err(&pdev->dev, "%s: no platform data supplied\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
struct resource *res;
|
||||
u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
|
||||
|
||||
alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
|
||||
if (!alg_data) {
|
||||
|
|
@ -585,14 +625,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, alg_data);
|
||||
|
||||
strlcpy(alg_data->adapter.name, i2c_pnx->name,
|
||||
sizeof(alg_data->adapter.name));
|
||||
alg_data->adapter.dev.parent = &pdev->dev;
|
||||
alg_data->adapter.algo = &pnx_algorithm;
|
||||
alg_data->adapter.algo_data = alg_data;
|
||||
alg_data->adapter.nr = pdev->id;
|
||||
alg_data->i2c_pnx = i2c_pnx;
|
||||
|
||||
alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
|
||||
#ifdef CONFIG_OF
|
||||
alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
|
||||
if (pdev->dev.of_node) {
|
||||
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&speed);
|
||||
/*
|
||||
* At this point, it is planned to add an OF timeout property.
|
||||
* As soon as there is a consensus about how to call and handle
|
||||
* this, sth. like the following can be put here:
|
||||
*
|
||||
* of_property_read_u32(pdev->dev.of_node, "timeout",
|
||||
* &alg_data->timeout);
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
alg_data->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(alg_data->clk)) {
|
||||
ret = PTR_ERR(alg_data->clk);
|
||||
|
|
@ -603,17 +656,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
alg_data->mif.timer.function = i2c_pnx_timeout;
|
||||
alg_data->mif.timer.data = (unsigned long)alg_data;
|
||||
|
||||
snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
|
||||
"%s", pdev->name);
|
||||
|
||||
/* Register I/O resource */
|
||||
if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Unable to get mem resource.\n");
|
||||
ret = -EBUSY;
|
||||
goto out_clkget;
|
||||
}
|
||||
if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE,
|
||||
pdev->name)) {
|
||||
dev_err(&pdev->dev,
|
||||
"I/O region 0x%08x for I2C already in use.\n",
|
||||
i2c_pnx->base);
|
||||
ret = -ENODEV;
|
||||
res->start);
|
||||
ret = -ENOMEM;
|
||||
goto out_clkget;
|
||||
}
|
||||
|
||||
alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
|
||||
alg_data->base = res->start;
|
||||
alg_data->ioaddr = ioremap(res->start, I2C_PNX_REGION_SIZE);
|
||||
if (!alg_data->ioaddr) {
|
||||
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -637,20 +700,25 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
* the deglitching filter length.
|
||||
*/
|
||||
|
||||
tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
|
||||
tmp = (freq / speed) / 2 - 2;
|
||||
if (tmp > 0x3FF)
|
||||
tmp = 0x3FF;
|
||||
iowrite32(tmp, I2C_REG_CKH(alg_data));
|
||||
iowrite32(tmp, I2C_REG_CKL(alg_data));
|
||||
|
||||
iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
|
||||
if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
|
||||
if (wait_reset(alg_data)) {
|
||||
ret = -ENODEV;
|
||||
goto out_clock;
|
||||
}
|
||||
init_completion(&alg_data->mif.complete);
|
||||
|
||||
ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
|
||||
alg_data->irq = platform_get_irq(pdev, 0);
|
||||
if (alg_data->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
|
||||
goto out_irq;
|
||||
}
|
||||
ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
|
||||
0, pdev->name, alg_data);
|
||||
if (ret)
|
||||
goto out_clock;
|
||||
|
|
@ -662,39 +730,39 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
|||
goto out_irq;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&alg_data->adapter);
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
|
||||
alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
|
||||
alg_data->adapter.name, res->start, alg_data->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
free_irq(i2c_pnx->irq, alg_data);
|
||||
free_irq(alg_data->irq, alg_data);
|
||||
out_clock:
|
||||
clk_disable(alg_data->clk);
|
||||
out_unmap:
|
||||
iounmap(alg_data->ioaddr);
|
||||
out_release:
|
||||
release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
|
||||
release_mem_region(res->start, I2C_PNX_REGION_SIZE);
|
||||
out_clkget:
|
||||
clk_put(alg_data->clk);
|
||||
out_drvdata:
|
||||
kfree(alg_data);
|
||||
err_kzalloc:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit i2c_pnx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
|
||||
struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
|
||||
|
||||
free_irq(i2c_pnx->irq, alg_data);
|
||||
free_irq(alg_data->irq, alg_data);
|
||||
i2c_del_adapter(&alg_data->adapter);
|
||||
clk_disable(alg_data->clk);
|
||||
iounmap(alg_data->ioaddr);
|
||||
release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
|
||||
release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
|
||||
clk_put(alg_data->clk);
|
||||
kfree(alg_data);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
|
@ -702,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id i2c_pnx_of_match[] = {
|
||||
{ .compatible = "nxp,pnx-i2c" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver i2c_pnx_driver = {
|
||||
.driver = {
|
||||
.name = "pnx-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(i2c_pnx_of_match),
|
||||
},
|
||||
.probe = i2c_pnx_probe,
|
||||
.remove = __devexit_p(i2c_pnx_remove),
|
||||
|
|
|
|||
Loading…
Reference in a new issue