Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2f2613b0
Commit
2f2613b0
authored
Sep 01, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/dspi' into spi-next
parents
96b1a28d
349ad66c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
607 additions
and
0 deletions
+607
-0
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+42
-0
drivers/spi/Kconfig
drivers/spi/Kconfig
+7
-0
drivers/spi/Makefile
drivers/spi/Makefile
+1
-0
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-dspi.c
+557
-0
No files found.
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
0 → 100644
View file @
2f2613b0
ARM Freescale DSPI controller
Required properties:
- compatible : "fsl,vf610-dspi"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
- clocks: from common clock binding: handle to dspi clock.
- clock-names: from common clock binding: Shall be "dspi".
- pinctrl-0: pin control group to be used for this controller.
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number.
Example:
dspi0@4002c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,vf610-dspi";
reg = <0x4002c000 0x1000>;
interrupts = <0 67 0x04>;
clocks = <&clks VF610_CLK_DSPI0>;
clock-names = "dspi";
spi-num-chipselects = <5>;
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
status = "okay";
sflash: at26df081a@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atmel,at26df081a";
spi-max-frequency = <16000000>;
spi-cpol;
spi-cpha;
reg = <0>;
linux,modalias = "m25p80";
modal = "at26df081a";
};
};
drivers/spi/Kconfig
View file @
2f2613b0
...
...
@@ -255,6 +255,13 @@ config SPI_FSL_SPI
This also enables using the Aeroflex Gaisler GRLIB SPI controller in
master mode.
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select SPI_BITBANG
help
This enables support for the Freescale DSPI controller in master
mode. VF610 platform uses the controller.
config SPI_FSL_ESPI
bool "Freescale eSPI controller"
depends on FSL_SOC
...
...
drivers/spi/Makefile
View file @
2f2613b0
...
...
@@ -31,6 +31,7 @@ spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EP93XX)
+=
spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON)
+=
spi-falcon.o
obj-$(CONFIG_SPI_FSL_CPM)
+=
spi-fsl-cpm.o
obj-$(CONFIG_SPI_FSL_DSPI)
+=
spi-fsl-dspi.o
obj-$(CONFIG_SPI_FSL_LIB)
+=
spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI)
+=
spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI)
+=
spi-fsl-spi.o
...
...
drivers/spi/spi-fsl-dspi.c
0 → 100644
View file @
2f2613b0
/*
* drivers/spi/spi-fsl-dspi.c
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* Freescale DSPI driver
* This file contains a driver for the Freescale DSPI
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define DRIVER_NAME "fsl-dspi"
#define TRAN_STATE_RX_VOID 0x01
#define TRAN_STATE_TX_VOID 0x02
#define TRAN_STATE_WORD_ODD_NUM 0x04
#define DSPI_FIFO_SIZE 4
#define SPI_MCR 0x00
#define SPI_MCR_MASTER (1 << 31)
#define SPI_MCR_PCSIS (0x3F << 16)
#define SPI_MCR_CLR_TXF (1 << 11)
#define SPI_MCR_CLR_RXF (1 << 10)
#define SPI_TCR 0x08
#define SPI_CTAR(x) (0x0c + (x * 4))
#define SPI_CTAR_FMSZ(x) (((x) & 0x0000000f) << 27)
#define SPI_CTAR_CPOL(x) ((x) << 26)
#define SPI_CTAR_CPHA(x) ((x) << 25)
#define SPI_CTAR_LSBFE(x) ((x) << 24)
#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22)
#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20)
#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18)
#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16)
#define SPI_CTAR_CSSCK(x) (((x) & 0x0000000f) << 12)
#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8)
#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4)
#define SPI_CTAR_BR(x) ((x) & 0x0000000f)
#define SPI_CTAR0_SLAVE 0x0c
#define SPI_SR 0x2c
#define SPI_SR_EOQF 0x10000000
#define SPI_RSER 0x30
#define SPI_RSER_EOQFE 0x10000000
#define SPI_PUSHR 0x34
#define SPI_PUSHR_CONT (1 << 31)
#define SPI_PUSHR_CTAS(x) (((x) & 0x00000007) << 28)
#define SPI_PUSHR_EOQ (1 << 27)
#define SPI_PUSHR_CTCNT (1 << 26)
#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16)
#define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff)
#define SPI_PUSHR_SLAVE 0x34
#define SPI_POPR 0x38
#define SPI_POPR_RXDATA(x) ((x) & 0x0000ffff)
#define SPI_TXFR0 0x3c
#define SPI_TXFR1 0x40
#define SPI_TXFR2 0x44
#define SPI_TXFR3 0x48
#define SPI_RXFR0 0x7c
#define SPI_RXFR1 0x80
#define SPI_RXFR2 0x84
#define SPI_RXFR3 0x88
#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1)
#define SPI_FRAME_BITS_MASK SPI_CTAR_FMSZ(0xf)
#define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf)
#define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7)
#define SPI_CS_INIT 0x01
#define SPI_CS_ASSERT 0x02
#define SPI_CS_DROP 0x04
struct
chip_data
{
u32
mcr_val
;
u32
ctar_val
;
u16
void_write_data
;
};
struct
fsl_dspi
{
struct
spi_bitbang
bitbang
;
struct
platform_device
*
pdev
;
void
*
base
;
int
irq
;
struct
clk
*
clk
;
struct
spi_transfer
*
cur_transfer
;
struct
chip_data
*
cur_chip
;
size_t
len
;
void
*
tx
;
void
*
tx_end
;
void
*
rx
;
void
*
rx_end
;
char
dataflags
;
u8
cs
;
u16
void_write_data
;
wait_queue_head_t
waitq
;
u32
waitflags
;
};
static
inline
int
is_double_byte_mode
(
struct
fsl_dspi
*
dspi
)
{
return
((
readl
(
dspi
->
base
+
SPI_CTAR
(
dspi
->
cs
))
&
SPI_FRAME_BITS_MASK
)
==
SPI_FRAME_BITS
(
8
))
?
0
:
1
;
}
static
void
set_bit_mode
(
struct
fsl_dspi
*
dspi
,
unsigned
char
bits
)
{
u32
temp
;
temp
=
readl
(
dspi
->
base
+
SPI_CTAR
(
dspi
->
cs
));
temp
&=
~
SPI_FRAME_BITS_MASK
;
temp
|=
SPI_FRAME_BITS
(
bits
);
writel
(
temp
,
dspi
->
base
+
SPI_CTAR
(
dspi
->
cs
));
}
static
void
hz_to_spi_baud
(
char
*
pbr
,
char
*
br
,
int
speed_hz
,
unsigned
long
clkrate
)
{
/* Valid baud rate pre-scaler values */
int
pbr_tbl
[
4
]
=
{
2
,
3
,
5
,
7
};
int
brs
[
16
]
=
{
2
,
4
,
6
,
8
,
16
,
32
,
64
,
128
,
256
,
512
,
1024
,
2048
,
4096
,
8192
,
16384
,
32768
};
int
temp
,
i
=
0
,
j
=
0
;
temp
=
clkrate
/
2
/
speed_hz
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pbr_tbl
);
i
++
)
for
(
j
=
0
;
j
<
ARRAY_SIZE
(
brs
);
j
++
)
{
if
(
pbr_tbl
[
i
]
*
brs
[
j
]
>=
temp
)
{
*
pbr
=
i
;
*
br
=
j
;
return
;
}
}
pr_warn
(
"Can not find valid buad rate,speed_hz is %d,clkrate is %ld\
,we use the max prescaler value.
\n
"
,
speed_hz
,
clkrate
);
*
pbr
=
ARRAY_SIZE
(
pbr_tbl
)
-
1
;
*
br
=
ARRAY_SIZE
(
brs
)
-
1
;
}
static
int
dspi_transfer_write
(
struct
fsl_dspi
*
dspi
)
{
int
tx_count
=
0
;
int
tx_word
;
u16
d16
;
u8
d8
;
u32
dspi_pushr
=
0
;
int
first
=
1
;
tx_word
=
is_double_byte_mode
(
dspi
);
/* If we are in word mode, but only have a single byte to transfer
* then switch to byte mode temporarily. Will switch back at the
* end of the transfer.
*/
if
(
tx_word
&&
(
dspi
->
len
==
1
))
{
dspi
->
dataflags
|=
TRAN_STATE_WORD_ODD_NUM
;
set_bit_mode
(
dspi
,
8
);
tx_word
=
0
;
}
while
(
dspi
->
len
&&
(
tx_count
<
DSPI_FIFO_SIZE
))
{
if
(
tx_word
)
{
if
(
dspi
->
len
==
1
)
break
;
if
(
!
(
dspi
->
dataflags
&
TRAN_STATE_TX_VOID
))
{
d16
=
*
(
u16
*
)
dspi
->
tx
;
dspi
->
tx
+=
2
;
}
else
{
d16
=
dspi
->
void_write_data
;
}
dspi_pushr
=
SPI_PUSHR_TXDATA
(
d16
)
|
SPI_PUSHR_PCS
(
dspi
->
cs
)
|
SPI_PUSHR_CTAS
(
dspi
->
cs
)
|
SPI_PUSHR_CONT
;
dspi
->
len
-=
2
;
}
else
{
if
(
!
(
dspi
->
dataflags
&
TRAN_STATE_TX_VOID
))
{
d8
=
*
(
u8
*
)
dspi
->
tx
;
dspi
->
tx
++
;
}
else
{
d8
=
(
u8
)
dspi
->
void_write_data
;
}
dspi_pushr
=
SPI_PUSHR_TXDATA
(
d8
)
|
SPI_PUSHR_PCS
(
dspi
->
cs
)
|
SPI_PUSHR_CTAS
(
dspi
->
cs
)
|
SPI_PUSHR_CONT
;
dspi
->
len
--
;
}
if
(
dspi
->
len
==
0
||
tx_count
==
DSPI_FIFO_SIZE
-
1
)
{
/* last transfer in the transfer */
dspi_pushr
|=
SPI_PUSHR_EOQ
;
}
else
if
(
tx_word
&&
(
dspi
->
len
==
1
))
dspi_pushr
|=
SPI_PUSHR_EOQ
;
if
(
first
)
{
first
=
0
;
dspi_pushr
|=
SPI_PUSHR_CTCNT
;
/* clear counter */
}
writel
(
dspi_pushr
,
dspi
->
base
+
SPI_PUSHR
);
tx_count
++
;
}
return
tx_count
*
(
tx_word
+
1
);
}
static
int
dspi_transfer_read
(
struct
fsl_dspi
*
dspi
)
{
int
rx_count
=
0
;
int
rx_word
=
is_double_byte_mode
(
dspi
);
u16
d
;
while
((
dspi
->
rx
<
dspi
->
rx_end
)
&&
(
rx_count
<
DSPI_FIFO_SIZE
))
{
if
(
rx_word
)
{
if
((
dspi
->
rx_end
-
dspi
->
rx
)
==
1
)
break
;
d
=
SPI_POPR_RXDATA
(
readl
(
dspi
->
base
+
SPI_POPR
));
if
(
!
(
dspi
->
dataflags
&
TRAN_STATE_RX_VOID
))
*
(
u16
*
)
dspi
->
rx
=
d
;
dspi
->
rx
+=
2
;
}
else
{
d
=
SPI_POPR_RXDATA
(
readl
(
dspi
->
base
+
SPI_POPR
));
if
(
!
(
dspi
->
dataflags
&
TRAN_STATE_RX_VOID
))
*
(
u8
*
)
dspi
->
rx
=
d
;
dspi
->
rx
++
;
}
rx_count
++
;
}
return
rx_count
;
}
static
int
dspi_txrx_transfer
(
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
)
{
struct
fsl_dspi
*
dspi
=
spi_master_get_devdata
(
spi
->
master
);
dspi
->
cur_transfer
=
t
;
dspi
->
cur_chip
=
spi_get_ctldata
(
spi
);
dspi
->
cs
=
spi
->
chip_select
;
dspi
->
void_write_data
=
dspi
->
cur_chip
->
void_write_data
;
dspi
->
dataflags
=
0
;
dspi
->
tx
=
(
void
*
)
t
->
tx_buf
;
dspi
->
tx_end
=
dspi
->
tx
+
t
->
len
;
dspi
->
rx
=
t
->
rx_buf
;
dspi
->
rx_end
=
dspi
->
rx
+
t
->
len
;
dspi
->
len
=
t
->
len
;
if
(
!
dspi
->
rx
)
dspi
->
dataflags
|=
TRAN_STATE_RX_VOID
;
if
(
!
dspi
->
tx
)
dspi
->
dataflags
|=
TRAN_STATE_TX_VOID
;
writel
(
dspi
->
cur_chip
->
mcr_val
,
dspi
->
base
+
SPI_MCR
);
writel
(
dspi
->
cur_chip
->
ctar_val
,
dspi
->
base
+
SPI_CTAR
(
dspi
->
cs
));
writel
(
SPI_RSER_EOQFE
,
dspi
->
base
+
SPI_RSER
);
if
(
t
->
speed_hz
)
writel
(
dspi
->
cur_chip
->
ctar_val
,
dspi
->
base
+
SPI_CTAR
(
dspi
->
cs
));
dspi_transfer_write
(
dspi
);
if
(
wait_event_interruptible
(
dspi
->
waitq
,
dspi
->
waitflags
))
dev_err
(
&
dspi
->
pdev
->
dev
,
"wait transfer complete fail!
\n
"
);
dspi
->
waitflags
=
0
;
return
t
->
len
-
dspi
->
len
;
}
static
void
dspi_chipselect
(
struct
spi_device
*
spi
,
int
value
)
{
struct
fsl_dspi
*
dspi
=
spi_master_get_devdata
(
spi
->
master
);
u32
pushr
=
readl
(
dspi
->
base
+
SPI_PUSHR
);
switch
(
value
)
{
case
BITBANG_CS_ACTIVE
:
pushr
|=
SPI_PUSHR_CONT
;
case
BITBANG_CS_INACTIVE
:
pushr
&=
~
SPI_PUSHR_CONT
;
}
writel
(
pushr
,
dspi
->
base
+
SPI_PUSHR
);
}
static
int
dspi_setup_transfer
(
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
)
{
struct
chip_data
*
chip
;
struct
fsl_dspi
*
dspi
=
spi_master_get_devdata
(
spi
->
master
);
unsigned
char
br
=
0
,
pbr
=
0
,
fmsz
=
0
;
/* Only alloc on first setup */
chip
=
spi_get_ctldata
(
spi
);
if
(
chip
==
NULL
)
{
chip
=
kcalloc
(
1
,
sizeof
(
struct
chip_data
),
GFP_KERNEL
);
if
(
!
chip
)
return
-
ENOMEM
;
}
chip
->
mcr_val
=
SPI_MCR_MASTER
|
SPI_MCR_PCSIS
|
SPI_MCR_CLR_TXF
|
SPI_MCR_CLR_RXF
;
if
((
spi
->
bits_per_word
>=
4
)
&&
(
spi
->
bits_per_word
<=
16
))
{
fmsz
=
spi
->
bits_per_word
-
1
;
}
else
{
pr_err
(
"Invalid wordsize
\n
"
);
kfree
(
chip
);
return
-
ENODEV
;
}
chip
->
void_write_data
=
0
;
hz_to_spi_baud
(
&
pbr
,
&
br
,
spi
->
max_speed_hz
,
clk_get_rate
(
dspi
->
clk
));
chip
->
ctar_val
=
SPI_CTAR_FMSZ
(
fmsz
)
|
SPI_CTAR_CPOL
(
spi
->
mode
&
SPI_CPOL
?
1
:
0
)
|
SPI_CTAR_CPHA
(
spi
->
mode
&
SPI_CPHA
?
1
:
0
)
|
SPI_CTAR_LSBFE
(
spi
->
mode
&
SPI_LSB_FIRST
?
1
:
0
)
|
SPI_CTAR_PBR
(
pbr
)
|
SPI_CTAR_BR
(
br
);
spi_set_ctldata
(
spi
,
chip
);
return
0
;
}
static
int
dspi_setup
(
struct
spi_device
*
spi
)
{
if
(
!
spi
->
max_speed_hz
)
return
-
EINVAL
;
if
(
!
spi
->
bits_per_word
)
spi
->
bits_per_word
=
8
;
return
dspi_setup_transfer
(
spi
,
NULL
);
}
static
irqreturn_t
dspi_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
fsl_dspi
*
dspi
=
(
struct
fsl_dspi
*
)
dev_id
;
writel
(
SPI_SR_EOQF
,
dspi
->
base
+
SPI_SR
);
dspi_transfer_read
(
dspi
);
if
(
!
dspi
->
len
)
{
if
(
dspi
->
dataflags
&
TRAN_STATE_WORD_ODD_NUM
)
set_bit_mode
(
dspi
,
16
);
dspi
->
waitflags
=
1
;
wake_up_interruptible
(
&
dspi
->
waitq
);
}
else
{
dspi_transfer_write
(
dspi
);
return
IRQ_HANDLED
;
}
return
IRQ_HANDLED
;
}
static
struct
of_device_id
fsl_dspi_dt_ids
[]
=
{
{
.
compatible
=
"fsl,vf610-dspi"
,
.
data
=
NULL
,
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
fsl_dspi_dt_ids
);
#ifdef CONFIG_PM_SLEEP
static
int
dspi_suspend
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
fsl_dspi
*
dspi
=
spi_master_get_devdata
(
master
);
spi_master_suspend
(
master
);
clk_disable_unprepare
(
dspi
->
clk
);
return
0
;
}
static
int
dspi_resume
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
fsl_dspi
*
dspi
=
spi_master_get_devdata
(
master
);
clk_prepare_enable
(
dspi
->
clk
);
spi_master_resume
(
master
);
return
0
;
}
#endif
/* CONFIG_PM_SLEEP */
static
const
struct
dev_pm_ops
dspi_pm
=
{
SET_SYSTEM_SLEEP_PM_OPS
(
dspi_suspend
,
dspi_resume
)
};
static
int
dspi_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
spi_master
*
master
;
struct
fsl_dspi
*
dspi
;
struct
resource
*
res
;
int
ret
=
0
,
cs_num
,
bus_num
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
struct
fsl_dspi
));
if
(
!
master
)
return
-
ENOMEM
;
dspi
=
spi_master_get_devdata
(
master
);
dspi
->
pdev
=
pdev
;
dspi
->
bitbang
.
master
=
spi_master_get
(
master
);
dspi
->
bitbang
.
chipselect
=
dspi_chipselect
;
dspi
->
bitbang
.
setup_transfer
=
dspi_setup_transfer
;
dspi
->
bitbang
.
txrx_bufs
=
dspi_txrx_transfer
;
dspi
->
bitbang
.
master
->
setup
=
dspi_setup
;
dspi
->
bitbang
.
master
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
4
)
|
SPI_BPW_MASK
(
8
)
|
SPI_BPW_MASK
(
16
);
ret
=
of_property_read_u32
(
np
,
"spi-num-chipselects"
,
&
cs_num
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"can't get spi-num-chipselects
\n
"
);
goto
out_master_put
;
}
master
->
num_chipselect
=
cs_num
;
ret
=
of_property_read_u32
(
np
,
"bus-num"
,
&
bus_num
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"can't get bus-num
\n
"
);
goto
out_master_put
;
}
master
->
bus_num
=
bus_num
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
dev_err
(
&
pdev
->
dev
,
"can't get platform resource
\n
"
);
ret
=
-
EINVAL
;
goto
out_master_put
;
}
dspi
->
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
!
dspi
->
base
)
{
ret
=
-
EINVAL
;
goto
out_master_put
;
}
dspi
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
dspi
->
irq
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"can't get platform irq
\n
"
);
ret
=
dspi
->
irq
;
goto
out_master_put
;
}
ret
=
devm_request_irq
(
&
pdev
->
dev
,
dspi
->
irq
,
dspi_interrupt
,
0
,
pdev
->
name
,
dspi
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Unable to attach DSPI interrupt
\n
"
);
goto
out_master_put
;
}
dspi
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
"dspi"
);
if
(
IS_ERR
(
dspi
->
clk
))
{
ret
=
PTR_ERR
(
dspi
->
clk
);
dev_err
(
&
pdev
->
dev
,
"unable to get clock
\n
"
);
goto
out_master_put
;
}
clk_prepare_enable
(
dspi
->
clk
);
init_waitqueue_head
(
&
dspi
->
waitq
);
platform_set_drvdata
(
pdev
,
dspi
);
ret
=
spi_bitbang_start
(
&
dspi
->
bitbang
);
if
(
ret
!=
0
)
{
dev_err
(
&
pdev
->
dev
,
"Problem registering DSPI master
\n
"
);
goto
out_clk_put
;
}
pr_info
(
KERN_INFO
"Freescale DSPI master initialized
\n
"
);
return
ret
;
out_clk_put:
clk_disable_unprepare
(
dspi
->
clk
);
out_master_put:
spi_master_put
(
master
);
platform_set_drvdata
(
pdev
,
NULL
);
return
ret
;
}
static
int
dspi_remove
(
struct
platform_device
*
pdev
)
{
struct
fsl_dspi
*
dspi
=
platform_get_drvdata
(
pdev
);
/* Disconnect from the SPI framework */
spi_bitbang_stop
(
&
dspi
->
bitbang
);
spi_master_put
(
dspi
->
bitbang
.
master
);
return
0
;
}
static
struct
platform_driver
fsl_dspi_driver
=
{
.
driver
.
name
=
DRIVER_NAME
,
.
driver
.
of_match_table
=
fsl_dspi_dt_ids
,
.
driver
.
owner
=
THIS_MODULE
,
.
driver
.
pm
=
&
dspi_pm
,
.
probe
=
dspi_probe
,
.
remove
=
dspi_remove
,
};
module_platform_driver
(
fsl_dspi_driver
);
MODULE_DESCRIPTION
(
"Freescale DSPI Controller Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:"
DRIVER_NAME
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment