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
d65d830c
Commit
d65d830c
authored
Jul 28, 2008
by
Benjamin Herrenschmidt
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'gcl/gcl-next'
parents
837b41b5
284b0189
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
317 additions
and
105 deletions
+317
-105
drivers/of/Kconfig
drivers/of/Kconfig
+6
-0
drivers/of/Makefile
drivers/of/Makefile
+1
-0
drivers/of/base.c
drivers/of/base.c
+88
-0
drivers/of/of_i2c.c
drivers/of/of_i2c.c
+3
-61
drivers/of/of_spi.c
drivers/of/of_spi.c
+93
-0
drivers/spi/spi.c
drivers/spi/spi.c
+95
-44
include/linux/of.h
include/linux/of.h
+1
-0
include/linux/of_spi.h
include/linux/of_spi.h
+18
-0
include/linux/spi/spi.h
include/linux/spi/spi.h
+12
-0
No files found.
drivers/of/Kconfig
View file @
d65d830c
...
...
@@ -13,3 +13,9 @@ config OF_I2C
depends on PPC_OF && I2C
help
OpenFirmware I2C accessors
config OF_SPI
def_tristate SPI
depends on OF && PPC_OF && SPI
help
OpenFirmware SPI accessors
drivers/of/Makefile
View file @
d65d830c
...
...
@@ -2,3 +2,4 @@ obj-y = base.o
obj-$(CONFIG_OF_DEVICE)
+=
device.o platform.o
obj-$(CONFIG_OF_GPIO)
+=
gpio.o
obj-$(CONFIG_OF_I2C)
+=
of_i2c.o
obj-$(CONFIG_OF_SPI)
+=
of_spi.o
drivers/of/base.c
View file @
d65d830c
...
...
@@ -385,3 +385,91 @@ struct device_node *of_find_matching_node(struct device_node *from,
return
np
;
}
EXPORT_SYMBOL
(
of_find_matching_node
);
/**
* of_modalias_table: Table of explicit compatible ==> modalias mappings
*
* This table allows particulare compatible property values to be mapped
* to modalias strings. This is useful for busses which do not directly
* understand the OF device tree but are populated based on data contained
* within the device tree. SPI and I2C are the two current users of this
* table.
*
* In most cases, devices do not need to be listed in this table because
* the modalias value can be derived directly from the compatible table.
* However, if for any reason a value cannot be derived, then this table
* provides a method to override the implicit derivation.
*
* At the moment, a single table is used for all bus types because it is
* assumed that the data size is small and that the compatible values
* should already be distinct enough to differentiate between SPI, I2C
* and other devices.
*/
struct
of_modalias_table
{
char
*
of_device
;
char
*
modalias
;
};
static
struct
of_modalias_table
of_modalias_table
[]
=
{
/* Empty for now; add entries as needed */
};
/**
* of_modalias_node - Lookup appropriate modalias for a device node
* @node: pointer to a device tree node
* @modalias: Pointer to buffer that modalias value will be copied into
* @len: Length of modalias value
*
* Based on the value of the compatible property, this routine will determine
* an appropriate modalias value for a particular device tree node. Three
* separate methods are used to derive a modalias value.
*
* First method is to lookup the compatible value in of_modalias_table.
* Second is to look for a "linux,<modalias>" entry in the compatible list
* and used that for modalias. Third is to strip off the manufacturer
* prefix from the first compatible entry and use the remainder as modalias
*
* This routine returns 0 on success
*/
int
of_modalias_node
(
struct
device_node
*
node
,
char
*
modalias
,
int
len
)
{
int
i
,
cplen
;
const
char
*
compatible
;
const
char
*
p
;
/* 1. search for exception list entry */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
of_modalias_table
);
i
++
)
{
compatible
=
of_modalias_table
[
i
].
of_device
;
if
(
!
of_device_is_compatible
(
node
,
compatible
))
continue
;
strlcpy
(
modalias
,
of_modalias_table
[
i
].
modalias
,
len
);
return
0
;
}
compatible
=
of_get_property
(
node
,
"compatible"
,
&
cplen
);
if
(
!
compatible
)
return
-
ENODEV
;
/* 2. search for linux,<modalias> entry */
p
=
compatible
;
while
(
cplen
>
0
)
{
if
(
!
strncmp
(
p
,
"linux,"
,
6
))
{
p
+=
6
;
strlcpy
(
modalias
,
p
,
len
);
return
0
;
}
i
=
strlen
(
p
)
+
1
;
p
+=
i
;
cplen
-=
i
;
}
/* 3. take first compatible entry and strip manufacturer */
p
=
strchr
(
compatible
,
','
);
if
(
!
p
)
return
-
ENODEV
;
p
++
;
strlcpy
(
modalias
,
p
,
len
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_modalias_node
);
drivers/of/of_i2c.c
View file @
d65d830c
...
...
@@ -16,62 +16,6 @@
#include <linux/of_i2c.h>
#include <linux/module.h>
struct
i2c_driver_device
{
char
*
of_device
;
char
*
i2c_type
;
};
static
struct
i2c_driver_device
i2c_devices
[]
=
{
};
static
int
of_find_i2c_driver
(
struct
device_node
*
node
,
struct
i2c_board_info
*
info
)
{
int
i
,
cplen
;
const
char
*
compatible
;
const
char
*
p
;
/* 1. search for exception list entry */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
i2c_devices
);
i
++
)
{
if
(
!
of_device_is_compatible
(
node
,
i2c_devices
[
i
].
of_device
))
continue
;
if
(
strlcpy
(
info
->
type
,
i2c_devices
[
i
].
i2c_type
,
I2C_NAME_SIZE
)
>=
I2C_NAME_SIZE
)
return
-
ENOMEM
;
return
0
;
}
compatible
=
of_get_property
(
node
,
"compatible"
,
&
cplen
);
if
(
!
compatible
)
return
-
ENODEV
;
/* 2. search for linux,<i2c-type> entry */
p
=
compatible
;
while
(
cplen
>
0
)
{
if
(
!
strncmp
(
p
,
"linux,"
,
6
))
{
p
+=
6
;
if
(
strlcpy
(
info
->
type
,
p
,
I2C_NAME_SIZE
)
>=
I2C_NAME_SIZE
)
return
-
ENOMEM
;
return
0
;
}
i
=
strlen
(
p
)
+
1
;
p
+=
i
;
cplen
-=
i
;
}
/* 3. take fist compatible entry and strip manufacturer */
p
=
strchr
(
compatible
,
','
);
if
(
!
p
)
return
-
ENODEV
;
p
++
;
if
(
strlcpy
(
info
->
type
,
p
,
I2C_NAME_SIZE
)
>=
I2C_NAME_SIZE
)
return
-
ENOMEM
;
return
0
;
}
void
of_register_i2c_devices
(
struct
i2c_adapter
*
adap
,
struct
device_node
*
adap_node
)
{
...
...
@@ -83,6 +27,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
const
u32
*
addr
;
int
len
;
if
(
of_modalias_node
(
node
,
info
.
type
,
sizeof
(
info
.
type
))
<
0
)
continue
;
addr
=
of_get_property
(
node
,
"reg"
,
&
len
);
if
(
!
addr
||
len
<
sizeof
(
int
)
||
*
addr
>
(
1
<<
10
)
-
1
)
{
printk
(
KERN_ERR
...
...
@@ -92,11 +39,6 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
info
.
irq
=
irq_of_parse_and_map
(
node
,
0
);
if
(
of_find_i2c_driver
(
node
,
&
info
)
<
0
)
{
irq_dispose_mapping
(
info
.
irq
);
continue
;
}
info
.
addr
=
*
addr
;
request_module
(
info
.
type
);
...
...
drivers/of/of_spi.c
0 → 100644
View file @
d65d830c
/*
* SPI OF support routines
* Copyright (C) 2008 Secret Lab Technologies Ltd.
*
* Support routines for deriving SPI device attachments from the device
* tree.
*/
#include <linux/of.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/of_spi.h>
/**
* of_register_spi_devices - Register child devices onto the SPI bus
* @master: Pointer to spi_master device
* @np: parent node of SPI device nodes
*
* Registers an spi_device for each child node of 'np' which has a 'reg'
* property.
*/
void
of_register_spi_devices
(
struct
spi_master
*
master
,
struct
device_node
*
np
)
{
struct
spi_device
*
spi
;
struct
device_node
*
nc
;
const
u32
*
prop
;
int
rc
;
int
len
;
for_each_child_of_node
(
np
,
nc
)
{
/* Alloc an spi_device */
spi
=
spi_alloc_device
(
master
);
if
(
!
spi
)
{
dev_err
(
&
master
->
dev
,
"spi_device alloc error for %s
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
/* Select device driver */
if
(
of_modalias_node
(
nc
,
spi
->
modalias
,
sizeof
(
spi
->
modalias
))
<
0
)
{
dev_err
(
&
master
->
dev
,
"cannot find modalias for %s
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
/* Device address */
prop
=
of_get_property
(
nc
,
"reg"
,
&
len
);
if
(
!
prop
||
len
<
sizeof
(
*
prop
))
{
dev_err
(
&
master
->
dev
,
"%s has no 'reg' property
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
spi
->
chip_select
=
*
prop
;
/* Mode (clock phase/polarity/etc.) */
if
(
of_find_property
(
nc
,
"spi-cpha"
,
NULL
))
spi
->
mode
|=
SPI_CPHA
;
if
(
of_find_property
(
nc
,
"spi-cpol"
,
NULL
))
spi
->
mode
|=
SPI_CPOL
;
/* Device speed */
prop
=
of_get_property
(
nc
,
"spi-max-frequency"
,
&
len
);
if
(
!
prop
||
len
<
sizeof
(
*
prop
))
{
dev_err
(
&
master
->
dev
,
"%s has no 'spi-max-frequency' property
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
spi
->
max_speed_hz
=
*
prop
;
/* IRQ */
spi
->
irq
=
irq_of_parse_and_map
(
nc
,
0
);
/* Store a pointer to the node in the device structure */
of_node_get
(
nc
);
spi
->
dev
.
archdata
.
of_node
=
nc
;
/* Register the new device */
request_module
(
spi
->
modalias
);
rc
=
spi_add_device
(
spi
);
if
(
rc
)
{
dev_err
(
&
master
->
dev
,
"spi_device register error %s
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
}
}
}
EXPORT_SYMBOL
(
of_register_spi_devices
);
drivers/spi/spi.c
View file @
d65d830c
...
...
@@ -178,6 +178,96 @@ struct boardinfo {
static
LIST_HEAD
(
board_list
);
static
DEFINE_MUTEX
(
board_lock
);
/**
* spi_alloc_device - Allocate a new SPI device
* @master: Controller to which device is connected
* Context: can sleep
*
* Allows a driver to allocate and initialize a spi_device without
* registering it immediately. This allows a driver to directly
* fill the spi_device with device parameters before calling
* spi_add_device() on it.
*
* Caller is responsible to call spi_add_device() on the returned
* spi_device structure to add it to the SPI master. If the caller
* needs to discard the spi_device without adding it, then it should
* call spi_dev_put() on it.
*
* Returns a pointer to the new device, or NULL.
*/
struct
spi_device
*
spi_alloc_device
(
struct
spi_master
*
master
)
{
struct
spi_device
*
spi
;
struct
device
*
dev
=
master
->
dev
.
parent
;
if
(
!
spi_master_get
(
master
))
return
NULL
;
spi
=
kzalloc
(
sizeof
*
spi
,
GFP_KERNEL
);
if
(
!
spi
)
{
dev_err
(
dev
,
"cannot alloc spi_device
\n
"
);
spi_master_put
(
master
);
return
NULL
;
}
spi
->
master
=
master
;
spi
->
dev
.
parent
=
dev
;
spi
->
dev
.
bus
=
&
spi_bus_type
;
spi
->
dev
.
release
=
spidev_release
;
device_initialize
(
&
spi
->
dev
);
return
spi
;
}
EXPORT_SYMBOL_GPL
(
spi_alloc_device
);
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
*
* Companion function to spi_alloc_device. Devices allocated with
* spi_alloc_device can be added onto the spi bus with this function.
*
* Returns 0 on success; non-zero on failure
*/
int
spi_add_device
(
struct
spi_device
*
spi
)
{
struct
device
*
dev
=
spi
->
master
->
dev
.
parent
;
int
status
;
/* Chipselects are numbered 0..max; validate. */
if
(
spi
->
chip_select
>=
spi
->
master
->
num_chipselect
)
{
dev_err
(
dev
,
"cs%d >= max %d
\n
"
,
spi
->
chip_select
,
spi
->
master
->
num_chipselect
);
return
-
EINVAL
;
}
/* Set the bus ID string */
snprintf
(
spi
->
dev
.
bus_id
,
sizeof
spi
->
dev
.
bus_id
,
"%s.%u"
,
spi
->
master
->
dev
.
bus_id
,
spi
->
chip_select
);
/* drivers may modify this initial i/o setup */
status
=
spi
->
master
->
setup
(
spi
);
if
(
status
<
0
)
{
dev_err
(
dev
,
"can't %s %s, status %d
\n
"
,
"setup"
,
spi
->
dev
.
bus_id
,
status
);
return
status
;
}
/* driver core catches callers that misbehave by defining
* devices that already exist.
*/
status
=
device_add
(
&
spi
->
dev
);
if
(
status
<
0
)
{
dev_err
(
dev
,
"can't %s %s, status %d
\n
"
,
"add"
,
spi
->
dev
.
bus_id
,
status
);
return
status
;
}
dev_dbg
(
dev
,
"registered child %s
\n
"
,
spi
->
dev
.
bus_id
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
spi_add_device
);
/**
* spi_new_device - instantiate one new SPI device
...
...
@@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master,
struct
spi_board_info
*
chip
)
{
struct
spi_device
*
proxy
;
struct
device
*
dev
=
master
->
dev
.
parent
;
int
status
;
/* NOTE: caller did any chip->bus_num checks necessary.
...
...
@@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master,
* suggests syslogged diagnostics are best here (ugh).
*/
/* Chipselects are numbered 0..max; validate. */
if
(
chip
->
chip_select
>=
master
->
num_chipselect
)
{
dev_err
(
dev
,
"cs%d > max %d
\n
"
,
chip
->
chip_select
,
master
->
num_chipselect
);
return
NULL
;
}
if
(
!
spi_master_get
(
master
))
proxy
=
spi_alloc_device
(
master
);
if
(
!
proxy
)
return
NULL
;
WARN_ON
(
strlen
(
chip
->
modalias
)
>=
sizeof
(
proxy
->
modalias
));
proxy
=
kzalloc
(
sizeof
*
proxy
,
GFP_KERNEL
);
if
(
!
proxy
)
{
dev_err
(
dev
,
"can't alloc dev for cs%d
\n
"
,
chip
->
chip_select
);
goto
fail
;
}
proxy
->
master
=
master
;
proxy
->
chip_select
=
chip
->
chip_select
;
proxy
->
max_speed_hz
=
chip
->
max_speed_hz
;
proxy
->
mode
=
chip
->
mode
;
proxy
->
irq
=
chip
->
irq
;
strlcpy
(
proxy
->
modalias
,
chip
->
modalias
,
sizeof
(
proxy
->
modalias
));
snprintf
(
proxy
->
dev
.
bus_id
,
sizeof
proxy
->
dev
.
bus_id
,
"%s.%u"
,
master
->
dev
.
bus_id
,
chip
->
chip_select
);
proxy
->
dev
.
parent
=
dev
;
proxy
->
dev
.
bus
=
&
spi_bus_type
;
proxy
->
dev
.
platform_data
=
(
void
*
)
chip
->
platform_data
;
proxy
->
controller_data
=
chip
->
controller_data
;
proxy
->
controller_state
=
NULL
;
proxy
->
dev
.
release
=
spidev_release
;
/* drivers may modify this initial i/o setup */
status
=
master
->
setup
(
proxy
);
status
=
spi_add_device
(
proxy
);
if
(
status
<
0
)
{
dev_err
(
dev
,
"can't %s %s, status %d
\n
"
,
"setup"
,
proxy
->
dev
.
bus_id
,
status
);
goto
fail
;
spi_dev_put
(
proxy
);
return
NULL
;
}
/* driver core catches callers that misbehave by defining
* devices that already exist.
*/
status
=
device_register
(
&
proxy
->
dev
);
if
(
status
<
0
)
{
dev_err
(
dev
,
"can't %s %s, status %d
\n
"
,
"add"
,
proxy
->
dev
.
bus_id
,
status
);
goto
fail
;
}
dev_dbg
(
dev
,
"registered child %s
\n
"
,
proxy
->
dev
.
bus_id
);
return
proxy
;
fail:
spi_master_put
(
master
);
kfree
(
proxy
);
return
NULL
;
}
EXPORT_SYMBOL_GPL
(
spi_new_device
);
...
...
include/linux/of.h
View file @
d65d830c
...
...
@@ -70,5 +70,6 @@ extern int of_n_addr_cells(struct device_node *np);
extern
int
of_n_size_cells
(
struct
device_node
*
np
);
extern
const
struct
of_device_id
*
of_match_node
(
const
struct
of_device_id
*
matches
,
const
struct
device_node
*
node
);
extern
int
of_modalias_node
(
struct
device_node
*
node
,
char
*
modalias
,
int
len
);
#endif
/* _LINUX_OF_H */
include/linux/of_spi.h
0 → 100644
View file @
d65d830c
/*
* OpenFirmware SPI support routines
* Copyright (C) 2008 Secret Lab Technologies Ltd.
*
* Support routines for deriving SPI device attachments from the device
* tree.
*/
#ifndef __LINUX_OF_SPI_H
#define __LINUX_OF_SPI_H
#include <linux/of.h>
#include <linux/spi/spi.h>
extern
void
of_register_spi_devices
(
struct
spi_master
*
master
,
struct
device_node
*
np
);
#endif
/* __LINUX_OF_SPI */
include/linux/spi/spi.h
View file @
d65d830c
...
...
@@ -778,7 +778,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* use spi_new_device() to describe each device. You can also call
* spi_unregister_device() to start making that device vanish, but
* normally that would be handled by spi_unregister_master().
*
* You can also use spi_alloc_device() and spi_add_device() to use a two
* stage registration sequence for each spi_device. This gives the caller
* some more control over the spi_device structure before it is registered,
* but requires that caller to initialize fields that would otherwise
* be defined using the board info.
*/
extern
struct
spi_device
*
spi_alloc_device
(
struct
spi_master
*
master
);
extern
int
spi_add_device
(
struct
spi_device
*
spi
);
extern
struct
spi_device
*
spi_new_device
(
struct
spi_master
*
,
struct
spi_board_info
*
);
...
...
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