* spidev.c driver on the ppc8247 (kernel 2.6.27.19)
@ 2009-03-18 7:36 Daniel Ng
2009-03-18 8:30 ` AW: " Stepanov, Sergej
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Ng @ 2009-03-18 7:36 UTC (permalink / raw)
To: linuxppc-dev
Hi,
I'm trying to get the spidev.c driver working in Kernel 2.6.27.19 on a ppc8247.
Firstly, would I need to convert it to an 'of'-style driver?
Assuming this is the case, I've changed spidev_init() to use
of_register_platform_driver() with what I think is an appropriate
parameter:
static struct of_platform_driver spidev_spi = {
.name = "spidev",
.match_table = spidev_match,
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
};
spidev_probe() now looks like the below. I've had to change the
spidev_probe() function signature, which meant I needed to use
to_spi_device() in the function (there are no other changes).
static int __devinit spidev_probe(struct of_device *ofdev, const
struct of_device_id *match)
{
struct spidev_data *spidev;
int status;
unsigned long minor;
struct spi_device *spi;
spi = to_spi_device(&ofdev->dev);
/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
return -ENOMEM;
/* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
/* If we can allocate a minor number, hook up this device.
* Reusing minors is fine so long as udev or mdev is working.
*/
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
dev = device_create_drvdata(spidev_class, &spi->dev,
spidev->devt, spidev,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
printk("spidev_probe(): CREATED spidev%d.%d\n",
spi->master->bus_num, spi->chip_select);
status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
.
.
/////// (the rest of this function is unchanged)
.
}
It all executes ok until the above call to device_create_drvdata(),
where it crashes (see below). Can anyone explain why?
Can I still use the 'old-style' device_create_drvdata() function with
the 'of new-style' driver framework?
Am I going about this the right way?
Unable to handle kernel paging request for data at address 0x00000120
Faulting instruction address: 0xc028e484
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT XXX
NIP: c028e484 LR: c028e478 CTR: c01511c8
REGS: c1819d60 TRAP: 0300 Not tainted (2.6.27.19-800-OS-03050107)
MSR: 00009032 <EE,ME,IR,DR> CR: 42044024 XER: 00000000
DAR: 00000120, DSISR: 20000000
TASK = c1814400[1] 'swapper' THREAD: c1818000
GPR00: c028e478 c1819e10 c1814400 0000000b 0000150c 0e400000 00000008 c0270000
GPR08: f0000038 00000000 0000150c c1818000 f0000020 fffffffe 01ff8000 00000000
GPR16: 01fed694 01ff56f0 00000000 00000000 00000000 00000000 c02d0000 c184ec10
GPR24: c02d2610 c1963288 c02d260c c02aafa4 00000000 ffffffed c1963280 c184ec10
NIP [c028e484] spidev_probe+0xec/0x1c8
LR [c028e478] spidev_probe+0xe0/0x1c8
Call Trace:
[c1819e10] [c028e478] spidev_probe+0xe0/0x1c8 (unreliable)
[c1819e40] [c01814a4] of_platform_device_probe+0x5c/0x84
[c1819e60] [c01552c8] driver_probe_device+0xe8/0x240
[c1819e90] [c01554a4] __driver_attach+0x84/0x88
[c1819eb0] [c01548fc] bus_for_each_dev+0x5c/0x98
[c1819ee0] [c01550a0] driver_attach+0x24/0x34
[c1819ef0] [c0154eac] bus_add_driver+0x1b4/0x220
[c1819f10] [c01557b4] driver_register+0x5c/0x158
[c1819f30] [c018136c] of_register_driver+0x54/0x70
[c1819f40] [c0289a28] spidev_init+0x6c/0xf8
[c1819f60] [c00038e8] do_one_initcall+0x38/0x188
[c1819fd0] [c0278180] kernel_init+0x8c/0xf8
[c1819ff0] [c000f6fc] kernel_thread+0x44/0x60
Instruction dump:
4be90481 2b83001f 7c7c1b78 419d00d8 64600e40 901e0000 3c60c027 38638f04
4bd8ea31 813f0120 80be0000 3ce0c027 <a9090120> 38e78f10 893f0128 7fe4fb78
---[ end trace 8d59482f3bf88fe6 ]---
Cheers,
Daniel
^ permalink raw reply [flat|nested] 8+ messages in thread
* AW: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-18 7:36 spidev.c driver on the ppc8247 (kernel 2.6.27.19) Daniel Ng
@ 2009-03-18 8:30 ` Stepanov, Sergej
2009-03-19 8:32 ` Daniel Ng
0 siblings, 1 reply; 8+ messages in thread
From: Stepanov, Sergej @ 2009-03-18 8:30 UTC (permalink / raw)
To: Daniel Ng, linuxppc-dev@ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 5738 bytes --]
Hi Daniel,
in the attachment i send a spi driver (little bit "of") done by myself
1.
to init it you can use the following in your dts-file
soc@f0000000 {
...
cpm@119c0 {
...
spi@11AA0 {
device_type = "spi";
compatible = "platform-mapped";
interrupts = <0x3F 8>;
interrupt-parent = <&pic>;
reg = <0x11AA0 0x60 0x89FC 2>;
};
...
}
2.
in driver/spi/Makefile
+obj-$(CONFIG_SPI_IDS8247) += spi_ids8247.o
3.
In driver/spi/Kconfig
config SPI_IDS8247
tristate "Freescale IDS8247 SPI controller"
depends on PPC_82xx && EXPERIMENTAL
help
This enables using the Freescale MPC8247
controllers in master mode.
Note, this driver uniquely supports the SPI controller on the MPC82xx
family of PowerPC processors.
This driver uses a simple set of shift registers for data
(opposed to the CPM based descriptor model).
4.
This version is for 2.6.27 kernel on ppc8247.
May be it help you and would be a bit faster for you.
Best regards
Sergej.
________________________________________
Von: linuxppc-dev-bounces+sergej.stepanov=ids.de@ozlabs.org [linuxppc-dev-bounces+sergej.stepanov=ids.de@ozlabs.org] im Auftrag von Daniel Ng [daniel.ng1234@gmail.com]
Gesendet: Mittwoch, 18. März 2009 08:36
An: linuxppc-dev@ozlabs.org
Betreff: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
Hi,
I'm trying to get the spidev.c driver working in Kernel 2.6.27.19 on a ppc8247.
Firstly, would I need to convert it to an 'of'-style driver?
Assuming this is the case, I've changed spidev_init() to use
of_register_platform_driver() with what I think is an appropriate
parameter:
static struct of_platform_driver spidev_spi = {
.name = "spidev",
.match_table = spidev_match,
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
};
spidev_probe() now looks like the below. I've had to change the
spidev_probe() function signature, which meant I needed to use
to_spi_device() in the function (there are no other changes).
static int __devinit spidev_probe(struct of_device *ofdev, const
struct of_device_id *match)
{
struct spidev_data *spidev;
int status;
unsigned long minor;
struct spi_device *spi;
spi = to_spi_device(&ofdev->dev);
/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
return -ENOMEM;
/* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
/* If we can allocate a minor number, hook up this device.
* Reusing minors is fine so long as udev or mdev is working.
*/
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
dev = device_create_drvdata(spidev_class, &spi->dev,
spidev->devt, spidev,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
printk("spidev_probe(): CREATED spidev%d.%d\n",
spi->master->bus_num, spi->chip_select);
status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
.
.
/////// (the rest of this function is unchanged)
.
}
It all executes ok until the above call to device_create_drvdata(),
where it crashes (see below). Can anyone explain why?
Can I still use the 'old-style' device_create_drvdata() function with
the 'of new-style' driver framework?
Am I going about this the right way?
Unable to handle kernel paging request for data at address 0x00000120
Faulting instruction address: 0xc028e484
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT XXX
NIP: c028e484 LR: c028e478 CTR: c01511c8
REGS: c1819d60 TRAP: 0300 Not tainted (2.6.27.19-800-OS-03050107)
MSR: 00009032 <EE,ME,IR,DR> CR: 42044024 XER: 00000000
DAR: 00000120, DSISR: 20000000
TASK = c1814400[1] 'swapper' THREAD: c1818000
GPR00: c028e478 c1819e10 c1814400 0000000b 0000150c 0e400000 00000008 c0270000
GPR08: f0000038 00000000 0000150c c1818000 f0000020 fffffffe 01ff8000 00000000
GPR16: 01fed694 01ff56f0 00000000 00000000 00000000 00000000 c02d0000 c184ec10
GPR24: c02d2610 c1963288 c02d260c c02aafa4 00000000 ffffffed c1963280 c184ec10
NIP [c028e484] spidev_probe+0xec/0x1c8
LR [c028e478] spidev_probe+0xe0/0x1c8
Call Trace:
[c1819e10] [c028e478] spidev_probe+0xe0/0x1c8 (unreliable)
[c1819e40] [c01814a4] of_platform_device_probe+0x5c/0x84
[c1819e60] [c01552c8] driver_probe_device+0xe8/0x240
[c1819e90] [c01554a4] __driver_attach+0x84/0x88
[c1819eb0] [c01548fc] bus_for_each_dev+0x5c/0x98
[c1819ee0] [c01550a0] driver_attach+0x24/0x34
[c1819ef0] [c0154eac] bus_add_driver+0x1b4/0x220
[c1819f10] [c01557b4] driver_register+0x5c/0x158
[c1819f30] [c018136c] of_register_driver+0x54/0x70
[c1819f40] [c0289a28] spidev_init+0x6c/0xf8
[c1819f60] [c00038e8] do_one_initcall+0x38/0x188
[c1819fd0] [c0278180] kernel_init+0x8c/0xf8
[c1819ff0] [c000f6fc] kernel_thread+0x44/0x60
Instruction dump:
4be90481 2b83001f 7c7c1b78 419d00d8 64600e40 901e0000 3c60c027 38638f04
4bd8ea31 813f0120 80be0000 3ce0c027 <a9090120> 38e78f10 893f0128 7fe4fb78
---[ end trace 8d59482f3bf88fe6 ]---
Cheers,
Daniel
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: spi_ids8247.c --]
[-- Type: text/x-csrc; name="spi_ids8247.c", Size: 20504 bytes --]
/*
* Simple IDS8247 SPI controller driver
* based on:
* MPC83xx SPI controller driver.
* from Kumar Gala
*
* Copyright (C) 2008 IDS GmbH.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/cpm2.h>
/* SPI Controller registers */
struct ids8247_spi_reg {
__be16 mode; /* 0x11AA0 */
__be32 rsv1; /* 0x11AA2 */
__be16 event; /* 0x11AA6 */
__be16 rsv2; /* 0x11AA8 */
__be16 mask; /* 0x11AAA */
__be16 rsv3; /* 0x11AAC */
__be16 command; /* 0x11AAD */
};
/*
* Default for SPI Mode:
* SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
*/
#define SPMODE_INIT_VAL (SPMODE_CI | SPMODE_CP | \
SPMODE_DIV16 | SPMODE_REV | \
SPMODE_MSTR | SPMODE_LEN(7) | SPMODE_PM(0x4))
/* SPIE register values */
#define SPIE_NE 0x0200 /* Not empty */
#define SPIE_NF 0x0100 /* Not full */
/* SPIM register values */
#define SPIM_NE 0x0200 /* Not empty */
#define SPIM_NF 0x0100 /* Not full */
#define MAX_RXBUFFS 8
#define MAX_TXBUFFS 8
#define MAX_LEN 512
struct spi_ram{
u16 rxbase; /* 0x00 */
u16 txbase; /* 0x02 */
u8 rfcr; /* 0x04 */
u8 tfcr; /* 0x05 */
u16 mrblr; /* 0x06 */
u32 rstate; /* 0x08 */
u32 cpuse1; /* 0x0c */
u16 rbptr; /* 0x10 */
u16 cpuse2; /* 0x12 */
u32 cpuse3; /* 0x14 */
u32 tstate; /* 0x18 */
u32 cpuse4; /* 0x1c */
u16 tbptr; /* 0x20 */
u16 cpuse5; /* 0x22 */
u32 cpuse[5]; /* 0x24-0x38 */
/* extra for bd of tx and rx */
};
/* SPI Controller driver's private data. */
struct ids8247_spi {
struct ids8247_spi_reg __iomem *base;
void __iomem *dpram;
struct spi_ram __iomem *spi_dpram;
/* rx & tx bufs from the spi_transfer */
// const void *tx;
// void *rx;
cbd_t __iomem *tx_vbase;
cbd_t __iomem *rx_vbase;
u8* rxbuf[MAX_RXBUFFS];
u8* txbuf[MAX_TXBUFFS];
u32 rxdma[MAX_RXBUFFS];
u32 txdma[MAX_TXBUFFS];
/* functions to deal with different sized buffers */
void (*get_rx) (u32 rx_data, struct ids8247_spi *);
u32(*get_tx) (struct ids8247_spi *);
unsigned int count;
int irq;
unsigned nsecs; /* (clock cycle time)/2 */
u32 spibrg; /* SPIBRG input clock */
u32 rxindex;
u32 txindex;
// u32 rx_shift; /* RX data reg shift when in qe mode */
// u32 tx_shift; /* TX data reg shift when in qe mode */
void (*activate_cs) (u8 cs, u8 polarity);
void (*deactivate_cs) (u8 cs, u8 polarity);
u8 busy;
struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
spinlock_t lock;
struct completion done;
};
struct spi_ids8247_cs {
/* functions to deal with different sized buffers */
void (*get_rx) (u32 rx_data, struct ids8247_spi *);
u32 (*get_tx) (struct ids8247_spi *);
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
u32 hw_mode; /* Holds HW mode register settings */
};
static inline void ids8247_spi_write_reg16(__be16 __iomem * reg, u16 val)
{
out_be16(reg, val);
}
static inline u16 ids8247_spi_read_reg16(__be16 __iomem * reg)
{
return in_be16(reg);
}
static inline void ids8247_spi_write_reg(__be32 __iomem * reg, u32 val)
{
out_be32(reg, val);
}
static inline u32 ids8247_spi_read_reg(__be32 __iomem * reg)
{
return in_be32(reg);
}
#if 0
#define IDS8247_SPI_RX_BUF(type) \
void ids8247_spi_rx_buf_##type(u32 data, struct ids8247_spi *ids8247_spi) \
{ \
type * rx = (type*)ids8247_spi->rxbuf; \
*rx++ = (type)(data >> ids8247_spi->rx_shift); \
ids8247_spi->rxbuf = (u8*)rx; \
}
#define IDS8247_SPI_TX_BUF(type) \
u32 ids8247_spi_tx_buf_##type(struct ids8247_spi *ids8247_spi) \
{ \
u32 data; \
const type * tx = (type*)ids8247_spi->txbuf; \
if (!tx) \
return 0; \
data = *tx++ << ids8247_spi->tx_shift; \
ids8247_spi->txbuf = (u8*)tx; \
return data; \
}
IDS8247_SPI_RX_BUF(u8)
IDS8247_SPI_RX_BUF(u16)
IDS8247_SPI_RX_BUF(u32)
IDS8247_SPI_TX_BUF(u8)
IDS8247_SPI_TX_BUF(u16)
IDS8247_SPI_TX_BUF(u32)
#endif
static void ids8247_spi_chipselect(struct spi_device *spi, int value)
{
struct ids8247_spi *ids8247_spi;
u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
struct spi_ids8247_cs *cs = spi->controller_state;
ids8247_spi = spi_master_get_devdata(spi->master);
if (value == BITBANG_CS_INACTIVE) {
if (ids8247_spi->deactivate_cs)
ids8247_spi->deactivate_cs(spi->chip_select, pol);
}
if (value == BITBANG_CS_ACTIVE) {
u32 regval = ids8247_spi_read_reg16(&ids8247_spi->base->mode);
//ids8247_spi->rx_shift = cs->rx_shift;
//ids8247_spi->tx_shift = cs->tx_shift;
ids8247_spi->get_rx = cs->get_rx;
ids8247_spi->get_tx = cs->get_tx;
if (cs->hw_mode != regval) {
unsigned long flags;
void *tmp_ptr = &ids8247_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time that
* SPI is disabled
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
ids8247_spi_write_reg(tmp_ptr, regval & ~SPMODE_EN);
ids8247_spi_write_reg(tmp_ptr, regval);
local_irq_restore(flags);
}
if (ids8247_spi->activate_cs)
ids8247_spi->activate_cs(spi->chip_select, pol);
}
}
static
int ids8247_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct ids8247_spi *ids8247_spi;
u32 regval;
u8 bits_per_word, pm;
u32 hz;
struct spi_ids8247_cs *cs = spi->controller_state;
ids8247_spi = spi_master_get_devdata(spi->master);
if (t) {
bits_per_word = t->bits_per_word;
hz = t->speed_hz;
} else {
bits_per_word = 0;
hz = 0;
}
/* spi_transfer level calls that work per-word */
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
cs->rx_shift = 0;
cs->tx_shift = 0;
if (bits_per_word <= 8) {
//cs->get_rx = ids8247_spi_rx_buf_u8;
//cs->get_tx = ids8247_spi_tx_buf_u8;
}
#if 0
else if (bits_per_word <= 16) {
cs->get_rx = ids8247_spi_rx_buf_u16;
cs->get_tx = ids8247_spi_tx_buf_u16;
} else if (bits_per_word <= 32) {
cs->get_rx = ids8247_spi_rx_buf_u32;
cs->get_tx = ids8247_spi_tx_buf_u32;
} else
return -EINVAL;
#endif
//ids8247_spi->rx_shift = cs->rx_shift;
//ids8247_spi->tx_shift = cs->tx_shift;
ids8247_spi->get_rx = cs->get_rx;
ids8247_spi->get_tx = cs->get_tx;
if (bits_per_word == 32)
bits_per_word = 0;
else
bits_per_word = bits_per_word - 1;
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
| SPMODE_PM(0xF));
cs->hw_mode |= SPMODE_LEN(bits_per_word);
if ((ids8247_spi->spibrg / hz) > 64) {
cs->hw_mode |= SPMODE_DIV16;
pm = ids8247_spi->spibrg / (hz * 64);
if (pm > 16) {
dev_err(&spi->dev, "Requested speed is too "
"low: %d Hz. Will use %d Hz instead.\n",
hz, ids8247_spi->spibrg / 1024);
pm = 16;
}
} else
pm = ids8247_spi->spibrg / (hz * 4);
if (pm)
pm--;
cs->hw_mode |= SPMODE_PM(pm);
regval = ids8247_spi_read_reg16(&ids8247_spi->base->mode);
if (cs->hw_mode != regval) {
unsigned long flags;
void *tmp_ptr = &ids8247_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time
* that SPI is disabled
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
ids8247_spi_write_reg(tmp_ptr, regval & ~SPMODE_EN);
ids8247_spi_write_reg(tmp_ptr, regval);
local_irq_restore(flags);
}
return 0;
}
static int ids8247_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct ids8247_spi *ids8247_spi;
u32 word, len, bits_per_word;
ids8247_spi = spi_master_get_devdata(spi->master);
memcpy(ids8247_spi->txbuf[ids8247_spi->txindex], t->tx_buf, t->len);
memcpy(t->rx_buf, ids8247_spi->rxbuf[ids8247_spi->rxindex], t->len);
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
len = t->len;
if (bits_per_word > 8) {
/* invalid length? */
if (len & 1)
return -EINVAL;
len /= 2;
}
if (bits_per_word > 16) {
/* invalid length? */
if (len & 1)
return -EINVAL;
len /= 2;
}
ids8247_spi->count = len;
INIT_COMPLETION(ids8247_spi->done);
setbits16( &ids8247_spi->tx_vbase[ids8247_spi->txindex].cbd_sc,
BD_SC_READY | BD_SC_LAST);
out_be16( &ids8247_spi->tx_vbase[ids8247_spi->txindex].cbd_datlen, t->len);
/* enable rx ints */
ids8247_spi_write_reg16(&ids8247_spi->base->mask, SPIM_NE);
setbits16(&ids8247_spi->base,
/* transmit word */
wait_for_completion(&ids8247_spi->done);
/* disable rx ints */
ids8247_spi_write_reg16(&ids8247_spi->base->mask, 0);
return ids8247_spi->count;
}
static void ids8247_spi_work(struct work_struct *work)
{
struct ids8247_spi *ids8247_spi =
container_of(work, struct ids8247_spi, work);
spin_lock_irq(&ids8247_spi->lock);
ids8247_spi->busy = 1;
while (!list_empty(&ids8247_spi->queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
unsigned cs_change;
int status, nsecs = 50;
m = container_of(ids8247_spi->queue.next,
struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&ids8247_spi->lock);
spi = m->spi;
cs_change = 1;
status = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
/* Don't allow changes if CS is active */
status = -EINVAL;
if (cs_change)
status = ids8247_spi_setup_transfer(spi, t);
if (status < 0)
break;
}
if (cs_change)
ids8247_spi_chipselect(spi, BITBANG_CS_ACTIVE);
cs_change = t->cs_change;
if (t->len)
status = ids8247_spi_bufs(spi, t);
if (status) {
status = -EMSGSIZE;
break;
}
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (cs_change) {
ndelay(nsecs);
ids8247_spi_chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
}
m->status = status;
m->complete(m->context);
if (status || !cs_change) {
ndelay(nsecs);
ids8247_spi_chipselect(spi, BITBANG_CS_INACTIVE);
}
ids8247_spi_setup_transfer(spi, NULL);
spin_lock_irq(&ids8247_spi->lock);
}
ids8247_spi->busy = 0;
spin_unlock_irq(&ids8247_spi->lock);
}
/* the spi->mode bits understood by this driver: */
#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_LOOP)
static int ids8247_spi_setup(struct spi_device *spi)
{
struct ids8247_spi *ids8247_spi;
int retval;
u32 hw_mode;
struct spi_ids8247_cs *cs = spi->controller_state;
if (spi->mode & ~MODEBITS) {
dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
spi->mode & ~MODEBITS);
return -EINVAL;
}
if (!spi->max_speed_hz)
return -EINVAL;
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
ids8247_spi = spi_master_get_devdata(spi->master);
if (!spi->bits_per_word)
spi->bits_per_word = 8;
hw_mode = cs->hw_mode; /* Save orginal settings */
cs->hw_mode = ids8247_spi_read_reg16(&ids8247_spi->base->mode);
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_CP | SPMODE_CI
| SPMODE_REV | SPMODE_LOOP);
if (spi->mode & SPI_CPHA)
cs->hw_mode |= SPMODE_CP;
if (spi->mode & SPI_CPOL)
cs->hw_mode |= SPMODE_CI;
if (!(spi->mode & SPI_LSB_FIRST))
cs->hw_mode |= SPMODE_REV;
if (spi->mode & SPI_LOOP)
cs->hw_mode |= SPMODE_LOOP;
retval = ids8247_spi_setup_transfer(spi, NULL);
if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */
return retval;
}
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n",
__func__, spi->mode & (SPI_CPOL | SPI_CPHA),
spi->bits_per_word, spi->max_speed_hz);
#if 0 /* Don't think this is needed */
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion
* between normal (active low) and inverted chipselects.
*/
/* deselect chip (low or high) */
spin_lock(&ids8247_spi->lock);
if (!ids8247_spi->busy)
ids8247_spi_chipselect(spi, BITBANG_CS_INACTIVE);
spin_unlock(&ids8247_spi->lock);
#endif
return 0;
}
irqreturn_t ids8247_spi_irq(s32 irq, void *context_data)
{
struct ids8247_spi *ids8247_spi = context_data;
u32 event;
irqreturn_t ret = IRQ_NONE;
/* Get interrupt events(tx/rx) */
event = ids8247_spi_read_reg16(&ids8247_spi->base->event);
/* We need handle RX first */
if (event & SPIE_NE) {
/* !!! u32 rx_data = ids8247_spi_read_reg(&ids8247_spi->base->receive);
if (ids8247_spi->rx)
ids8247_spi->get_rx(rx_data, ids8247_spi);*/
//out_be(ids8247_spi->rx_vbase[ids8247_spi->rxinidex],cbd_sc, BD_SC_EMPTY);
ids8247_spi->rxindex = (ids8247_spi->rxindex++) % MAX_RXBUFFS;
ret = IRQ_HANDLED;
}
if ((event & SPIE_NF) == 0)
/* spin until TX is done */
while (((event =
ids8247_spi_read_reg16(&ids8247_spi->base->event)) &
SPIE_NF) == 0)
cpu_relax();
ids8247_spi->count -= 1;
if (ids8247_spi->count) {
// u32 word = ids8247_spi->get_tx(ids8247_spi);
// !!! ids8247_spi_write_reg(&ids8247_spi->base->transmit, word);
ids8247_spi->txindex = (ids8247_spi->txindex++) % MAX_RXBUFFS;
} else {
complete(&ids8247_spi->done);
}
/* Clear the events */
ids8247_spi_write_reg16(&ids8247_spi->base->event, event);
return ret;
}
static int ids8247_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct ids8247_spi *ids8247_spi = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&ids8247_spi->lock, flags);
list_add_tail(&m->queue, &ids8247_spi->queue);
queue_work(ids8247_spi->workqueue, &ids8247_spi->work);
spin_unlock_irqrestore(&ids8247_spi->lock, flags);
return 0;
}
static void ids8247_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static int __init ids8247_spi_probe(struct platform_device *dev)
{
struct spi_master *master;
struct ids8247_spi *ids8247_spi;
struct fsl_spi_platform_data *pdata;
struct resource *r;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
u32 regval;
int ret = 0, i;
unsigned long dpramoffset = 0, dprxtxoffsave = 0;
/* Get resources(memory, IRQ) associated with the device */
master = spi_alloc_master(&dev->dev, sizeof(struct ids8247_spi));
if (master == NULL) {
ret = -ENOMEM;
goto err;
}
platform_set_drvdata(dev, master);
pdata = dev->dev.platform_data;
if (pdata == NULL) {
ret = -ENODEV;
goto free_master;
}
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (r == NULL) {
ret = -ENODEV;
goto free_master;
}
master->setup = ids8247_spi_setup;
master->transfer = ids8247_spi_transfer;
master->cleanup = ids8247_spi_cleanup;
ids8247_spi = spi_master_get_devdata(master);
ids8247_spi->activate_cs = pdata->activate_cs;
ids8247_spi->deactivate_cs = pdata->deactivate_cs;
ids8247_spi->spibrg = pdata->sysclk;
// !!! ids8247_spi->get_rx = ids8247_spi_rx_buf_u8;
// !!! ids8247_spi->get_tx = ids8247_spi_tx_buf_u8;
//ids8247_spi->rx_shift = 0;
//ids8247_spi->tx_shift = 0;
ids8247_spi->rxindex = 0;
ids8247_spi->txindex = 0;
init_completion(&ids8247_spi->done);
ids8247_spi->base = ioremap(r->start, r->end - r->start + 1);
if (ids8247_spi->base == NULL) {
ret = -ENOMEM;
goto put_master;
}
r = platform_get_resource(dev, IORESOURCE_MEM, 1);
if (r == NULL) {
ret = -ENODEV;
goto free_master;
}
ids8247_spi->dpram = ioremap(r->start, r->end - r->start + 1);
if (ids8247_spi->dpram == NULL) {
ret = -ENOMEM;
goto put_master;
}
/* docu 35-10 */
dpramoffset = cpm_dpalloc( sizeof(struct spi_ram), 64);
out_be16( (u16*)ids8247_spi->dpram, (u16)(dpramoffset & 0xFFFF));
iounmap(ids8247_spi->dpram);
ids8247_spi->dpram = NULL;
ids8247_spi->spi_dpram = ioremap( get_immrbase() + dpramoffset,
sizeof(struct spi_ram));
memset(ids8247_spi->spi_dpram, 0, sizeof(struct spi_ram));
dpramoffset = cpm_dpalloc( sizeof(cbd_t) * (MAX_RXBUFFS + MAX_TXBUFFS), 8);
ids8247_spi->spi_dpram->rxbase = dpramoffset;
ids8247_spi->rx_vbase = cpm_muram_addr(dpramoffset);
ids8247_spi->spi_dpram->txbase = dpramoffset + sizeof(cbd_t) * MAX_RXBUFFS;
ids8247_spi->tx_vbase = cpm_muram_addr(dpramoffset
+ sizeof(cbd_t) * MAX_RXBUFFS);
rbdf = ids8247_spi->rx_vbase;
tbdf = ids8247_spi->tx_vbase;
/* now it is ready for init of bd's */
for (i = 0; i < MAX_RXBUFFS; i++) {
ids8247_spi->rxbuf[i] = dma_alloc_coherent(
NULL, MAX_LEN + 1, &ids8247_spi->rxdma[i], GFP_KERNEL);
if (!ids8247_spi->rxbuf[i]) {
ret = -ENOMEM;
goto put_master;
}
out_be32(&rbdf[i].cbd_bufaddr, ((ids8247_spi->rxdma[i] + 1) & ~1));
out_be16(&rbdf->cbd_datlen, 0);
out_be16(&rbdf[i].cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
}
setbits16(&rbdf[i].cbd_sc, BD_SC_WRAP);
for (i = 0; i < MAX_TXBUFFS; i++) {
ids8247_spi->txbuf[i] = (unsigned char *)dma_alloc_coherent(
NULL, MAX_LEN + 1, &ids8247_spi->txdma[i], GFP_KERNEL);
if (!ids8247_spi->txbuf[i]) {
ret = -ENOMEM;
goto out_muram;
}
out_be32(&tbdf[i].cbd_bufaddr, ids8247_spi->txdma[i]);
out_be16(&tbdf->cbd_datlen, 0);
out_be16(&tbdf[i].cbd_sc, BD_SC_INTRPT);
}
setbits16(&tbdf[i].cbd_sc, BD_SC_WRAP);
ids8247_spi->spi_dpram->rfcr = 0x10;
ids8247_spi->spi_dpram->tfcr = 0x10;
ids8247_spi->spi_dpram->mrblr = MAX_LEN;
ids8247_spi->irq = platform_get_irq(dev, 0);
if (ids8247_spi->irq < 0) {
ret = -ENXIO;
goto unmap_io;
}
/* Register for SPI Interrupt */
ret = request_irq(ids8247_spi->irq, ids8247_spi_irq,
0, "ids8247_spi", ids8247_spi);
if (ret != 0)
goto unmap_io;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
/* SPI controller initializations */
ids8247_spi_write_reg16(&ids8247_spi->base->mode, 0);
ids8247_spi_write_reg16(&ids8247_spi->base->mask, 0);
ids8247_spi_write_reg16(&ids8247_spi->base->command, 0);
ids8247_spi_write_reg16(&ids8247_spi->base->event, 0xff00);
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_EN;
ids8247_spi_write_reg16(&ids8247_spi->base->mode, regval);
spin_lock_init(&ids8247_spi->lock);
init_completion(&ids8247_spi->done);
INIT_WORK(&ids8247_spi->work, ids8247_spi_work);
INIT_LIST_HEAD(&ids8247_spi->queue);
ids8247_spi->workqueue = create_singlethread_workqueue(
master->dev.parent->bus_id);
if (ids8247_spi->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
cpm_command(0x25400000, 0);
ret = spi_register_master(master);
if (ret < 0)
goto unreg_master;
printk(KERN_INFO
"%s: ids8247 SPI Controller driver at 0x%p (irq = %d)\n",
dev->dev.bus_id, ids8247_spi->base, ids8247_spi->irq);
return ret;
/*TODO: real cleanup */
out_muram:
unreg_master:
destroy_workqueue(ids8247_spi->workqueue);
free_irq:
free_irq(ids8247_spi->irq, ids8247_spi);
unmap_io:
iounmap(ids8247_spi->base);
put_master:
spi_master_put(master);
free_master:
kfree(master);
err:
return ret;
}
static int __exit ids8247_spi_remove(struct platform_device *dev)
{
struct ids8247_spi *ids8247_spi;
struct spi_master *master;
master = platform_get_drvdata(dev);
ids8247_spi = spi_master_get_devdata(master);
flush_workqueue(ids8247_spi->workqueue);
destroy_workqueue(ids8247_spi->workqueue);
spi_unregister_master(master);
free_irq(ids8247_spi->irq, ids8247_spi);
iounmap(ids8247_spi->base);
return 0;
}
MODULE_ALIAS("platform:ids8247_spi");
static struct platform_driver ids8247_spi_driver = {
.remove = __exit_p(ids8247_spi_remove),
.driver = {
.name = "ids8247_spi",
.owner = THIS_MODULE,
},
};
static int __init ids8247_spi_init(void)
{
return platform_driver_probe(&ids8247_spi_driver, ids8247_spi_probe);
}
static void __exit ids8247_spi_exit(void)
{
platform_driver_unregister(&ids8247_spi_driver);
}
module_init(ids8247_spi_init);
module_exit(ids8247_spi_exit);
MODULE_AUTHOR("Sergej Stepanov");
MODULE_DESCRIPTION("Simple MPC8247 SPI Driver");
MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-18 8:30 ` AW: " Stepanov, Sergej
@ 2009-03-19 8:32 ` Daniel Ng
2009-03-20 1:19 ` Daniel Ng
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Ng @ 2009-03-19 8:32 UTC (permalink / raw)
To: Stepanov, Sergej; +Cc: linuxppc-dev@ozlabs.org
Hi Sergej,
On Wed, Mar 18, 2009 at 7:30 PM, Stepanov, Sergej
<Sergej.Stepanov@ids.de> wrote:
> in the attachment i send a spi driver (little bit "of") done by myself
Thanks for your driver. I've already got a SPI Controller driver, I
just want to hook it up to spidev.c so that it is has a Userspace
interface via /dev/spi-0.
I'm looking at the I2C driver for some ideas.
i2cdev_attach_adapter() handles the creation of the /dev/i2c-0 dev
node, and associates the i2c driver with this dev node.
cpm_i2c_probe() seems to end up calling i2cdev_attach_adapter() via
the following chain:
cpm_i2c_probe() -> i2c_add_adapter() -> i2c_register_adapter() ->
i2c_do_add_adaptor -> i2cdev_attach_adapter()
It seems like spidev_probe() does generally the same thing as
i2cdev_attach_adapter() for SPI.
So, I tried to call spidev_probe() directly from the probe() function
of my SPI Controller driver. However in this case spidev_probe()
failed because its call to device_create_drvdata() failed with error
code ENODEV. Why would this be?
This is how I make the call from my SPI Controller driver:
spidev_probe(to_spi_device(&ofdev->dev));
And this is the relevant code in spidev_probe():
dev = device_create_drvdata(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
/*spi->master->bus_num*/0, spi->chip_select);
Note that if I uncomment the spi->master->bus_num parameter and get
rid of the hacked-in '0', the above results in a crash. I guess this
means that spi->master has not been set up. But it *has* been set up
in my SPI Controller's probe() function using platform_set_drvdata():
static int __devinit XXX_spi_probe(struct of_device *ofdev, const
struct of_device_id *match)
{
struct spi_master *master;
struct XXX_spi *sp;
int res=0;
master = spi_alloc_master(&ofdev->dev, sizeof(struct XXX_spi));
if (master == NULL) {
dev_err(&ofdev->dev, "failed to allocate spi master\n");
return -ENOMEM;
}
master->bus_num = 0;
master->num_chipselect = XXX_MAX_CHIPSEL;
sp = spi_master_get_devdata(master);
platform_set_drvdata(ofdev, sp);
res = spidev_probe(to_spi_device(&ofdev->dev));
if(res)
{
printk("XXX_spi_probe()- spidev_probe() FAILED\n");
}
return res;
}
Inserting the below just before the call to spidev_probe() solves the
problem of the crash:
{
struct spi_device *spidev;
spidev = to_spi_device(&ofdev->dev);
spidev->master = master;
}
But I still get the ENODEV error mentioned above. Can anyone explain why?
Cheers,
Daniel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-19 8:32 ` Daniel Ng
@ 2009-03-20 1:19 ` Daniel Ng
2009-03-20 9:37 ` AW: " Stepanov, Sergej
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Ng @ 2009-03-20 1:19 UTC (permalink / raw)
To: Stepanov, Sergej; +Cc: linuxppc-dev@ozlabs.org
On Thu, Mar 19, 2009 at 7:32 PM, Daniel Ng <daniel.ng1234@gmail.com> wrote:
>
> So, I tried to call spidev_probe() directly from the probe() function
> of my SPI Controller driver. However in this case spidev_probe()
> failed because its call to device_create_drvdata() failed with error
> code ENODEV. Why would this be?
>
> This is how I make the call from my SPI Controller driver:
>
> spidev_probe(to_spi_device(&ofdev->dev));
>
> And this is the relevant code in spidev_probe():
>
> dev =3D device_create_drvdata(spidev_class, &spi->dev, spidev->devt,
> spidev, "spidev%d.%d",
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*spi->master=
->bus_num*/0, spi->chip_select);
It looks like spidev_class was uninitialised because spidev_init() had
not yet been called. To force spidev_init() to be called before my SPI
Controller's driver initialisation, I just used:
subsys_initcall(spidev_init);
This seems to do the job...
^ permalink raw reply [flat|nested] 8+ messages in thread
* AW: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-20 1:19 ` Daniel Ng
@ 2009-03-20 9:37 ` Stepanov, Sergej
2009-03-24 5:05 ` Daniel Ng
0 siblings, 1 reply; 8+ messages in thread
From: Stepanov, Sergej @ 2009-03-20 9:37 UTC (permalink / raw)
To: Daniel Ng; +Cc: linuxppc-dev@ozlabs.org
Hi Daniel,
sorry, my example was incomplete...
for a fast you can add in your platform file something like this:
..........................
#ifdef CONFIG_SPI_IDS8247
#include <linux/spi/spi.h>
#include <linux/spi/mmc_spi.h>
#include <linux/mmc/host.h>
#endif
........
#ifdef CONFIG_SPI_IDS8247
#define GPIO_CS (224+22)
static void ids8247_spi_activate_cs(u8 cs, u8 polarity)
{
pr_debug("%s %d %d\n", __func__, cs, polarity);
//gpio_set_value(GPIO_CS, (int)polarity);
}
static void ids8247_spi_deactivate_cs(u8 cs, u8 polarity)
{
pr_debug("%s %d %d\n", __func__, cs, polarity);
//gpio_set_value(GPIO_CS, (int)(!polarity));
}
static struct mmc_spi_platform_data ids8247_mmc_pdata =3D {
.ocr_mask =3D MMC_VDD_32_33,
};
static struct spi_board_info ids8247_spi_boardinfo =3D {
.bus_num =3D 0,
.chip_select =3D 0,
.max_speed_hz =3D 20000000,
.modalias =3D "mmc_spi",
.platform_data =3D &ids8247_mmc_pdata,
};
static __init int ids8247_spi_setup(void)
{
int ret =3D 0;
struct platform_device *spi_dev;
struct resource r[3];
struct device_node *np =3D NULL;
struct fsl_spi_platform_data spi_data;
/*if (!gpio_get_value(GPIO_CS))
return;
*/
if( (np =3D of_find_compatible_node(NULL, "spi", "platform-mapped")) =3D=
=3D0 )
return 0;
//fsl_get_sys_freq();
memset(&spi_data, 0, sizeof(struct fsl_spi_platform_data));
spi_data.activate_cs =3D ids8247_spi_activate_cs;
spi_data.deactivate_cs =3D ids8247_spi_deactivate_cs;
spi_data.bus_num =3D 0;
spi_data.max_chipselect =3D 1;
memset(r, 0, sizeof(struct resource)*3);
ret =3D of_address_to_resource(np, 0, &r[0]);
if (ret)
goto spi_err;
ret =3D of_address_to_resource(np, 1, &r[1]);
if (ret)
goto spi_err;
ret =3D of_irq_to_resource(np, 0, &r[2]);
if (ret =3D=3D NO_IRQ)
goto spi_err;
spi_data.qe_mode =3D 0;
spi_data.sysclk =3D 24750000;
spi_dev =3D platform_device_register_simple("ids8247_spi", 0, &r[0], 3);
if (IS_ERR(spi_dev)) {
ret =3D PTR_ERR(spi_dev);
return ret;
}
ret =3D platform_device_add_data(spi_dev,
&spi_data,
sizeof(struct fsl_spi_platform_data));
if(ret) {
platform_device_unregister(spi_dev);
return ret;
}
of_node_put(np);
return spi_register_board_info(&ids8247_spi_boardinfo, 1);
spi_err:
of_node_put(np);
return -1;
}
arch_initcall(ids8247_spi_setup);
#endif /* CONFIG_SPI_IDS8247 */
..........
Sorry, i know it looks very dirty...
Regards
Sergej.
________________________________________
Von: Daniel Ng [daniel.ng1234@gmail.com]
Gesendet: Freitag, 20. M=E4rz 2009 02:19
An: Stepanov, Sergej
Cc: linuxppc-dev@ozlabs.org
Betreff: Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
On Thu, Mar 19, 2009 at 7:32 PM, Daniel Ng <daniel.ng1234@gmail.com> wrote:
>
> So, I tried to call spidev_probe() directly from the probe() function
> of my SPI Controller driver. However in this case spidev_probe()
> failed because its call to device_create_drvdata() failed with error
> code ENODEV. Why would this be?
>
> This is how I make the call from my SPI Controller driver:
>
> spidev_probe(to_spi_device(&ofdev->dev));
>
> And this is the relevant code in spidev_probe():
>
> dev =3D device_create_drvdata(spidev_class, &spi->dev, spidev->devt,
> spidev, "spidev%d.%d",
> /*spi->master->bus_num*/0, spi->chip_select=
);
It looks like spidev_class was uninitialised because spidev_init() had
not yet been called. To force spidev_init() to be called before my SPI
Controller's driver initialisation, I just used:
subsys_initcall(spidev_init);
This seems to do the job...
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-20 9:37 ` AW: " Stepanov, Sergej
@ 2009-03-24 5:05 ` Daniel Ng
2019-06-06 13:14 ` siva krishna
2019-06-06 13:15 ` siva krishna
0 siblings, 2 replies; 8+ messages in thread
From: Daniel Ng @ 2009-03-24 5:05 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org
The solution is in Documentation/spi/spidev:
-in the slave device spi_board_info struct, specify 'spidev' for the
'modalias' of *every* SPI slave.
I wonder what magic was involved to set this up!!?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-24 5:05 ` Daniel Ng
@ 2019-06-06 13:14 ` siva krishna
2019-06-06 13:15 ` siva krishna
1 sibling, 0 replies; 8+ messages in thread
From: siva krishna @ 2019-06-06 13:14 UTC (permalink / raw)
To: linuxppc-dev
Hi ,
can you elobarate this ,meaning which file need to be modified etc .
--
Sent from: http://linuxppc.10917.n7.nabble.com/linuxppc-dev-f3.html
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: spidev.c driver on the ppc8247 (kernel 2.6.27.19)
2009-03-24 5:05 ` Daniel Ng
2019-06-06 13:14 ` siva krishna
@ 2019-06-06 13:15 ` siva krishna
1 sibling, 0 replies; 8+ messages in thread
From: siva krishna @ 2019-06-06 13:15 UTC (permalink / raw)
To: linuxppc-dev
can yo explain little more on this
--
Sent from: http://linuxppc.10917.n7.nabble.com/linuxppc-dev-f3.html
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-06-06 14:00 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-18 7:36 spidev.c driver on the ppc8247 (kernel 2.6.27.19) Daniel Ng
2009-03-18 8:30 ` AW: " Stepanov, Sergej
2009-03-19 8:32 ` Daniel Ng
2009-03-20 1:19 ` Daniel Ng
2009-03-20 9:37 ` AW: " Stepanov, Sergej
2009-03-24 5:05 ` Daniel Ng
2019-06-06 13:14 ` siva krishna
2019-06-06 13:15 ` siva krishna
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).