mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
Merge branch 'akpm' (Andrew's incoming - part two)
Says Andrew: "60 patches. That's good enough for -rc1 I guess. I have quite a lot of detritus to be rechecked, work through maintainers, etc. - most of the remains of MM - rtc - various misc - cgroups - memcg - cpusets - procfs - ipc - rapidio - sysctl - pps - w1 - drivers/misc - aio" * akpm: (60 commits) memcg: replace ss->id_lock with a rwlock aio: allocate kiocbs in batches drivers/misc/vmw_balloon.c: fix typo in code comment drivers/misc/vmw_balloon.c: determine page allocation flag can_sleep outside loop w1: disable irqs in critical section drivers/w1/w1_int.c: multiple masters used same init_name drivers/power/ds2780_battery.c: fix deadlock upon insertion and removal drivers/power/ds2780_battery.c: add a nolock function to w1 interface drivers/power/ds2780_battery.c: create central point for calling w1 interface w1: ds2760 and ds2780, use ida for id and ida_simple_get() to get it pps gpio client: add missing dependency pps: new client driver using GPIO pps: default echo function include/linux/dma-mapping.h: add dma_zalloc_coherent() sysctl: make CONFIG_SYSCTL_SYSCALL default to n sysctl: add support for poll() RapidIO: documentation update drivers/net/rionet.c: fix ethernet address macros for LE platforms RapidIO: fix potential null deref in rio_setup_device() RapidIO: add mport driver for Tsi721 bridge ...
This commit is contained in:
@@ -50,6 +50,13 @@ specify the GFP_ flags (see kmalloc) for the allocation (the
|
||||
implementation may choose to ignore flags that affect the location of
|
||||
the returned memory, like GFP_DMA).
|
||||
|
||||
void *
|
||||
dma_zalloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
|
||||
Wraps dma_alloc_coherent() and also zeroes the returned memory if the
|
||||
allocation attempt succeeded.
|
||||
|
||||
void
|
||||
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_handle)
|
||||
|
||||
@@ -418,7 +418,6 @@ total_unevictable - sum of all children's "unevictable"
|
||||
|
||||
# The following additional stats are dependent on CONFIG_DEBUG_VM.
|
||||
|
||||
inactive_ratio - VM internal parameter. (see mm/page_alloc.c)
|
||||
recent_rotated_anon - VM internal parameter. (see mm/vmscan.c)
|
||||
recent_rotated_file - VM internal parameter. (see mm/vmscan.c)
|
||||
recent_scanned_anon - VM internal parameter. (see mm/vmscan.c)
|
||||
|
||||
@@ -133,41 +133,6 @@ Who: Pavel Machek <pavel@ucw.cz>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: sys_sysctl
|
||||
When: September 2010
|
||||
Option: CONFIG_SYSCTL_SYSCALL
|
||||
Why: The same information is available in a more convenient from
|
||||
/proc/sys, and none of the sysctl variables appear to be
|
||||
important performance wise.
|
||||
|
||||
Binary sysctls are a long standing source of subtle kernel
|
||||
bugs and security issues.
|
||||
|
||||
When I looked several months ago all I could find after
|
||||
searching several distributions were 5 user space programs and
|
||||
glibc (which falls back to /proc/sys) using this syscall.
|
||||
|
||||
The man page for sysctl(2) documents it as unusable for user
|
||||
space programs.
|
||||
|
||||
sysctl(2) is not generally ABI compatible to a 32bit user
|
||||
space application on a 64bit and a 32bit kernel.
|
||||
|
||||
For the last several months the policy has been no new binary
|
||||
sysctls and no one has put forward an argument to use them.
|
||||
|
||||
Binary sysctls issues seem to keep happening appearing so
|
||||
properly deprecating them (with a warning to user space) and a
|
||||
2 year grace warning period will mean eventually we can kill
|
||||
them and end the pain.
|
||||
|
||||
In the mean time individual binary sysctls can be dealt with
|
||||
in a piecewise fashion.
|
||||
|
||||
Who: Eric Biederman <ebiederm@xmission.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: /proc/<pid>/oom_adj
|
||||
When: August 2012
|
||||
Why: /proc/<pid>/oom_adj allows userspace to influence the oom killer's
|
||||
|
||||
@@ -144,7 +144,7 @@ and the default device ID in order to access the device on the active port.
|
||||
|
||||
After the host has completed enumeration of the entire network it releases
|
||||
devices by clearing device ID locks (calls rio_clear_locks()). For each endpoint
|
||||
in the system, it sets the Master Enable bit in the Port General Control CSR
|
||||
in the system, it sets the Discovered bit in the Port General Control CSR
|
||||
to indicate that enumeration is completed and agents are allowed to execute
|
||||
passive discovery of the network.
|
||||
|
||||
|
||||
49
Documentation/rapidio/tsi721.txt
Normal file
49
Documentation/rapidio/tsi721.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
RapidIO subsystem mport driver for IDT Tsi721 PCI Express-to-SRIO bridge.
|
||||
=========================================================================
|
||||
|
||||
I. Overview
|
||||
|
||||
This driver implements all currently defined RapidIO mport callback functions.
|
||||
It supports maintenance read and write operations, inbound and outbound RapidIO
|
||||
doorbells, inbound maintenance port-writes and RapidIO messaging.
|
||||
|
||||
To generate SRIO maintenance transactions this driver uses one of Tsi721 DMA
|
||||
channels. This mechanism provides access to larger range of hop counts and
|
||||
destination IDs without need for changes in outbound window translation.
|
||||
|
||||
RapidIO messaging support uses dedicated messaging channels for each mailbox.
|
||||
For inbound messages this driver uses destination ID matching to forward messages
|
||||
into the corresponding message queue. Messaging callbacks are implemented to be
|
||||
fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
|
||||
|
||||
II. Known problems
|
||||
|
||||
None.
|
||||
|
||||
III. To do
|
||||
|
||||
Add DMA data transfers (non-messaging).
|
||||
Add inbound region (SRIO-to-PCIe) mapping.
|
||||
|
||||
IV. Version History
|
||||
|
||||
1.0.0 - Initial driver release.
|
||||
|
||||
V. License
|
||||
-----------------------------------------------
|
||||
|
||||
Copyright(c) 2011 Integrated Device Technology, Inc. All rights reserved.
|
||||
|
||||
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.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
@@ -16,16 +16,6 @@
|
||||
|
||||
#ifdef __HAVE_ARCH_PTE_SPECIAL
|
||||
|
||||
static inline void get_huge_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* __split_huge_page_refcount() cannot run
|
||||
* from under us.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) < 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* The performance critical leaf functions are made noinline otherwise gcc
|
||||
* inlines everything into a single function which results in too much
|
||||
@@ -57,8 +47,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
||||
put_page(page);
|
||||
return 0;
|
||||
}
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
||||
{
|
||||
unsigned long mask;
|
||||
unsigned long pte_end;
|
||||
struct page *head, *page;
|
||||
struct page *head, *page, *tail;
|
||||
pte_t pte;
|
||||
int refs;
|
||||
|
||||
@@ -413,6 +413,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
||||
head = pte_page(pte);
|
||||
|
||||
page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
@@ -428,10 +429,20 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
||||
|
||||
if (unlikely(pte_val(pte) != pte_val(*ptep))) {
|
||||
/* Could be optimized better */
|
||||
while (*nr) {
|
||||
put_page(page);
|
||||
(*nr)--;
|
||||
}
|
||||
*nr -= refs;
|
||||
while (refs--)
|
||||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -1608,6 +1608,7 @@ int fsl_rio_setup(struct platform_device *dev)
|
||||
return 0;
|
||||
err:
|
||||
iounmap(priv->regs_win);
|
||||
release_resource(&port->iores);
|
||||
err_res:
|
||||
kfree(priv);
|
||||
err_priv:
|
||||
|
||||
@@ -52,7 +52,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask, result;
|
||||
struct page *head, *page;
|
||||
struct page *head, *page, *tail;
|
||||
int refs;
|
||||
|
||||
result = write ? 0 : _SEGMENT_ENTRY_RO;
|
||||
@@ -64,6 +64,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||
refs = 0;
|
||||
head = pmd_page(pmd);
|
||||
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
@@ -81,6 +82,17 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||
*nr -= refs;
|
||||
while (refs--)
|
||||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -56,6 +56,8 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
||||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
if (head != page)
|
||||
get_huge_page_tail(page);
|
||||
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
||||
@@ -108,16 +108,6 @@ static inline void get_head_page_multiple(struct page *page, int nr)
|
||||
SetPageReferenced(page);
|
||||
}
|
||||
|
||||
static inline void get_huge_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* __split_huge_page_refcount() cannot run
|
||||
* from under us.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) < 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
|
||||
@@ -151,7 +151,7 @@ MODULE_LICENSE("GPL");
|
||||
struct vmballoon_stats {
|
||||
unsigned int timer;
|
||||
|
||||
/* allocation statustics */
|
||||
/* allocation statistics */
|
||||
unsigned int alloc;
|
||||
unsigned int alloc_fail;
|
||||
unsigned int sleep_alloc;
|
||||
@@ -412,6 +412,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
|
||||
gfp_t flags;
|
||||
unsigned int hv_status;
|
||||
bool locked = false;
|
||||
flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP;
|
||||
|
||||
do {
|
||||
if (!can_sleep)
|
||||
@@ -419,7 +420,6 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
|
||||
else
|
||||
STATS_INC(b->stats.sleep_alloc);
|
||||
|
||||
flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP;
|
||||
page = alloc_page(flags);
|
||||
if (!page) {
|
||||
if (!can_sleep)
|
||||
|
||||
@@ -88,8 +88,8 @@ static struct rio_dev **rionet_active;
|
||||
#define dev_rionet_capable(dev) \
|
||||
is_rionet_capable(dev->src_ops, dev->dst_ops)
|
||||
|
||||
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
|
||||
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
|
||||
#define RIONET_MAC_MATCH(x) (!memcmp((x), "\00\01\00\01", 4))
|
||||
#define RIONET_GET_DESTID(x) ((*((u8 *)x + 4) << 8) | *((u8 *)x + 5))
|
||||
|
||||
static int rionet_rx_clean(struct net_device *ndev)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ struct ds2780_device_info {
|
||||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
struct device *w1_dev;
|
||||
struct task_struct *mutex_holder;
|
||||
};
|
||||
|
||||
enum current_types {
|
||||
@@ -49,8 +50,8 @@ enum current_types {
|
||||
static const char model[] = "DS2780";
|
||||
static const char manufacturer[] = "Maxim/Dallas";
|
||||
|
||||
static inline struct ds2780_device_info *to_ds2780_device_info(
|
||||
struct power_supply *psy)
|
||||
static inline struct ds2780_device_info *
|
||||
to_ds2780_device_info(struct power_supply *psy)
|
||||
{
|
||||
return container_of(psy, struct ds2780_device_info, bat);
|
||||
}
|
||||
@@ -60,17 +61,28 @@ static inline struct power_supply *to_power_supply(struct device *dev)
|
||||
return dev_get_drvdata(dev);
|
||||
}
|
||||
|
||||
static inline int ds2780_read8(struct device *dev, u8 *val, int addr)
|
||||
static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
|
||||
char *buf, int addr, size_t count, int io)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, sizeof(u8), 0);
|
||||
if (dev_info->mutex_holder == current)
|
||||
return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
|
||||
else
|
||||
return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
|
||||
}
|
||||
|
||||
static int ds2780_read16(struct device *dev, s16 *val, int addr)
|
||||
static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
|
||||
int addr)
|
||||
{
|
||||
return ds2780_battery_io(dev_info, val, addr, sizeof(u8), 0);
|
||||
}
|
||||
|
||||
static int ds2780_read16(struct ds2780_device_info *dev_info, s16 *val,
|
||||
int addr)
|
||||
{
|
||||
int ret;
|
||||
u8 raw[2];
|
||||
|
||||
ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0);
|
||||
ret = ds2780_battery_io(dev_info, raw, addr, sizeof(raw), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -79,16 +91,16 @@ static int ds2780_read16(struct device *dev, s16 *val, int addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ds2780_read_block(struct device *dev, u8 *val, int addr,
|
||||
size_t count)
|
||||
static inline int ds2780_read_block(struct ds2780_device_info *dev_info,
|
||||
u8 *val, int addr, size_t count)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, count, 0);
|
||||
return ds2780_battery_io(dev_info, val, addr, count, 0);
|
||||
}
|
||||
|
||||
static inline int ds2780_write(struct device *dev, u8 *val, int addr,
|
||||
size_t count)
|
||||
static inline int ds2780_write(struct ds2780_device_info *dev_info, u8 *val,
|
||||
int addr, size_t count)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, count, 1);
|
||||
return ds2780_battery_io(dev_info, val, addr, count, 1);
|
||||
}
|
||||
|
||||
static inline int ds2780_store_eeprom(struct device *dev, int addr)
|
||||
@@ -122,7 +134,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &conductance,
|
||||
ret = ds2780_write(dev_info, &conductance,
|
||||
DS2780_RSNSP_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -134,7 +146,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
|
||||
static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info,
|
||||
u16 *rsgain)
|
||||
{
|
||||
return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG);
|
||||
return ds2780_read16(dev_info, rsgain, DS2780_RSGAIN_MSB_REG);
|
||||
}
|
||||
|
||||
/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
|
||||
@@ -144,8 +156,8 @@ static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info,
|
||||
int ret;
|
||||
u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, raw,
|
||||
DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2);
|
||||
ret = ds2780_write(dev_info, raw,
|
||||
DS2780_RSGAIN_MSB_REG, sizeof(raw));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -167,7 +179,7 @@ static int ds2780_get_voltage(struct ds2780_device_info *dev_info,
|
||||
* Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
|
||||
* voltage LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &voltage_raw,
|
||||
ret = ds2780_read16(dev_info, &voltage_raw,
|
||||
DS2780_VOLT_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -196,7 +208,7 @@ static int ds2780_get_temperature(struct ds2780_device_info *dev_info,
|
||||
* Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
|
||||
* temperature LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &temperature_raw,
|
||||
ret = ds2780_read16(dev_info, &temperature_raw,
|
||||
DS2780_TEMP_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -222,13 +234,13 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info,
|
||||
* The units of measurement for current are dependent on the value of
|
||||
* the sense resistor.
|
||||
*/
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (sense_res_raw == 0) {
|
||||
dev_err(dev_info->dev, "sense resistor value is 0\n");
|
||||
return -ENXIO;
|
||||
return -EINVAL;
|
||||
}
|
||||
sense_res = 1000 / sense_res_raw;
|
||||
|
||||
@@ -248,7 +260,7 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info,
|
||||
* Bits 7 - 0 of the current value are in bits 7 - 0 of the current
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, reg_msb);
|
||||
ret = ds2780_read16(dev_info, ¤t_raw, reg_msb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -267,7 +279,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
|
||||
* The units of measurement for accumulated current are dependent on
|
||||
* the value of the sense resistor.
|
||||
*/
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -285,7 +297,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
|
||||
* Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, DS2780_ACR_MSB_REG);
|
||||
ret = ds2780_read16(dev_info, ¤t_raw, DS2780_ACR_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -299,7 +311,7 @@ static int ds2780_get_capacity(struct ds2780_device_info *dev_info,
|
||||
int ret;
|
||||
u8 raw;
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG);
|
||||
ret = ds2780_read8(dev_info, &raw, DS2780_RARC_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -345,7 +357,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
|
||||
* Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG);
|
||||
ret = ds2780_read16(dev_info, &charge_raw, DS2780_RAAC_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -356,7 +368,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
|
||||
static int ds2780_get_control_register(struct ds2780_device_info *dev_info,
|
||||
u8 *control_reg)
|
||||
{
|
||||
return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG);
|
||||
return ds2780_read8(dev_info, control_reg, DS2780_CONTROL_REG);
|
||||
}
|
||||
|
||||
static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
|
||||
@@ -364,7 +376,7 @@ static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &control_reg,
|
||||
ret = ds2780_write(dev_info, &control_reg,
|
||||
DS2780_CONTROL_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -503,7 +515,7 @@ static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
|
||||
struct power_supply *psy = to_power_supply(dev);
|
||||
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_resistor, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -584,7 +596,7 @@ static ssize_t ds2780_get_pio_pin(struct device *dev,
|
||||
struct power_supply *psy = to_power_supply(dev);
|
||||
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG);
|
||||
ret = ds2780_read8(dev_info, &sfr, DS2780_SFR_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -611,7 +623,7 @@ static ssize_t ds2780_set_pio_pin(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &new_setting,
|
||||
ret = ds2780_write(dev_info, &new_setting,
|
||||
DS2780_SFR_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -632,7 +644,7 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
|
||||
DS2780_EEPROM_BLOCK1_END -
|
||||
DS2780_EEPROM_BLOCK1_START + 1 - off);
|
||||
|
||||
return ds2780_read_block(dev_info->w1_dev, buf,
|
||||
return ds2780_read_block(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK1_START + off, count);
|
||||
}
|
||||
|
||||
@@ -650,7 +662,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
|
||||
DS2780_EEPROM_BLOCK1_END -
|
||||
DS2780_EEPROM_BLOCK1_START + 1 - off);
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, buf,
|
||||
ret = ds2780_write(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK1_START + off, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -685,9 +697,8 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
|
||||
DS2780_EEPROM_BLOCK0_END -
|
||||
DS2780_EEPROM_BLOCK0_START + 1 - off);
|
||||
|
||||
return ds2780_read_block(dev_info->w1_dev, buf,
|
||||
return ds2780_read_block(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK0_START + off, count);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
||||
@@ -704,7 +715,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
||||
DS2780_EEPROM_BLOCK0_END -
|
||||
DS2780_EEPROM_BLOCK0_START + 1 - off);
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, buf,
|
||||
ret = ds2780_write(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK0_START + off, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -768,6 +779,7 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
||||
dev_info->bat.properties = ds2780_battery_props;
|
||||
dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props);
|
||||
dev_info->bat.get_property = ds2780_battery_get_property;
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &dev_info->bat);
|
||||
if (ret) {
|
||||
@@ -797,6 +809,8 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
||||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
dev_info->mutex_holder = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
@@ -816,6 +830,8 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
/* remove attributes */
|
||||
sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
|
||||
|
||||
|
||||
@@ -29,4 +29,13 @@ config PPS_CLIENT_PARPORT
|
||||
If you say yes here you get support for a PPS source connected
|
||||
with the interrupt pin of your parallel port.
|
||||
|
||||
config PPS_CLIENT_GPIO
|
||||
tristate "PPS client using GPIO"
|
||||
depends on PPS && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for a PPS source using
|
||||
GPIO. To be useful you must also register a platform device
|
||||
specifying the GPIO pin and other options, usually in your board
|
||||
setup.
|
||||
|
||||
endif
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
|
||||
obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
|
||||
obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
|
||||
obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o
|
||||
|
||||
ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
|
||||
|
||||
227
drivers/pps/clients/pps-gpio.c
Normal file
227
drivers/pps/clients/pps-gpio.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* pps-gpio.c -- PPS client driver using GPIO
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
|
||||
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define PPS_GPIO_NAME "pps-gpio"
|
||||
#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pps_kernel.h>
|
||||
#include <linux/pps-gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/* Info for each registered platform device */
|
||||
struct pps_gpio_device_data {
|
||||
int irq; /* IRQ used as PPS source */
|
||||
struct pps_device *pps; /* PPS source device */
|
||||
struct pps_source_info info; /* PPS source information */
|
||||
const struct pps_gpio_platform_data *pdata;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report the PPS event
|
||||
*/
|
||||
|
||||
static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
|
||||
{
|
||||
const struct pps_gpio_device_data *info;
|
||||
struct pps_event_time ts;
|
||||
int rising_edge;
|
||||
|
||||
/* Get the time stamp first */
|
||||
pps_get_ts(&ts);
|
||||
|
||||
info = data;
|
||||
|
||||
rising_edge = gpio_get_value(info->pdata->gpio_pin);
|
||||
if ((rising_edge && !info->pdata->assert_falling_edge) ||
|
||||
(!rising_edge && info->pdata->assert_falling_edge))
|
||||
pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
|
||||
else if (info->pdata->capture_clear &&
|
||||
((rising_edge && info->pdata->assert_falling_edge) ||
|
||||
(!rising_edge && !info->pdata->assert_falling_edge)))
|
||||
pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pps_gpio_setup(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
|
||||
if (ret) {
|
||||
pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gpio_direction_input(pdata->gpio_pin);
|
||||
if (ret) {
|
||||
pr_warning("failed to set pin direction\n");
|
||||
gpio_free(pdata->gpio_pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
|
||||
{
|
||||
unsigned long flags = pdata->assert_falling_edge ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
|
||||
if (pdata->capture_clear) {
|
||||
flags |= ((flags & IRQF_TRIGGER_RISING) ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int pps_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pps_gpio_device_data *data;
|
||||
int irq;
|
||||
int ret;
|
||||
int err;
|
||||
int pps_default_params;
|
||||
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
|
||||
/* GPIO setup */
|
||||
ret = pps_gpio_setup(pdev);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
/* IRQ setup */
|
||||
irq = gpio_to_irq(pdata->gpio_pin);
|
||||
if (irq < 0) {
|
||||
pr_err("failed to map GPIO to IRQ: %d\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* allocate space for device info */
|
||||
data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
|
||||
if (data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* initialize PPS specific parts of the bookkeeping data structure. */
|
||||
data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
|
||||
PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
|
||||
if (pdata->capture_clear)
|
||||
data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
|
||||
PPS_ECHOCLEAR;
|
||||
data->info.owner = THIS_MODULE;
|
||||
snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
|
||||
pdev->name, pdev->id);
|
||||
|
||||
/* register PPS source */
|
||||
pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
|
||||
if (pdata->capture_clear)
|
||||
pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
|
||||
data->pps = pps_register_source(&data->info, pps_default_params);
|
||||
if (data->pps == NULL) {
|
||||
kfree(data);
|
||||
pr_err("failed to register IRQ %d as PPS source\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
data->irq = irq;
|
||||
data->pdata = pdata;
|
||||
|
||||
/* register IRQ interrupt handler */
|
||||
ret = request_irq(irq, pps_gpio_irq_handler,
|
||||
get_irqf_trigger_flags(pdata), data->info.name, data);
|
||||
if (ret) {
|
||||
pps_unregister_source(data->pps);
|
||||
kfree(data);
|
||||
pr_err("failed to acquire IRQ %d\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
|
||||
|
||||
return 0;
|
||||
|
||||
return_error:
|
||||
gpio_free(pdata->gpio_pin);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pps_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
|
||||
const struct pps_gpio_platform_data *pdata = data->pdata;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
free_irq(data->irq, data);
|
||||
gpio_free(pdata->gpio_pin);
|
||||
pps_unregister_source(data->pps);
|
||||
pr_info("removed IRQ %d as PPS source\n", data->irq);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pps_gpio_driver = {
|
||||
.probe = pps_gpio_probe,
|
||||
.remove = __devexit_p(pps_gpio_remove),
|
||||
.driver = {
|
||||
.name = PPS_GPIO_NAME,
|
||||
.owner = THIS_MODULE
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pps_gpio_init(void)
|
||||
{
|
||||
int ret = platform_driver_register(&pps_gpio_driver);
|
||||
if (ret < 0)
|
||||
pr_err("failed to register platform driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit pps_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pps_gpio_driver);
|
||||
pr_debug("unregistered platform driver\n");
|
||||
}
|
||||
|
||||
module_init(pps_gpio_init);
|
||||
module_exit(pps_gpio_exit);
|
||||
|
||||
MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
|
||||
MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
|
||||
MODULE_DESCRIPTION("Use GPIO pin as PPS source");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("1.0.0");
|
||||
@@ -51,17 +51,6 @@ static void pps_ktimer_event(unsigned long ptr)
|
||||
mod_timer(&ktimer, jiffies + HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* The echo function
|
||||
*/
|
||||
|
||||
static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* The PPS info struct
|
||||
*/
|
||||
@@ -72,7 +61,6 @@ static struct pps_source_info pps_ktimer_info = {
|
||||
.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
|
||||
PPS_ECHOASSERT |
|
||||
PPS_CANWAIT | PPS_TSFMT_TSPEC,
|
||||
.echo = pps_ktimer_echo,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -133,14 +133,6 @@ out_both:
|
||||
return;
|
||||
}
|
||||
|
||||
/* the PPS echo function */
|
||||
static void pps_echo(struct pps_device *pps, int event, void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
static void parport_attach(struct parport *port)
|
||||
{
|
||||
struct pps_client_pp *device;
|
||||
@@ -151,7 +143,6 @@ static void parport_attach(struct parport *port)
|
||||
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
|
||||
PPS_ECHOASSERT | PPS_ECHOCLEAR | \
|
||||
PPS_CANWAIT | PPS_TSFMT_TSPEC,
|
||||
.echo = pps_echo,
|
||||
.owner = THIS_MODULE,
|
||||
.dev = NULL
|
||||
};
|
||||
|
||||
@@ -52,6 +52,14 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
|
||||
ts->sec += offset->sec;
|
||||
}
|
||||
|
||||
static void pps_echo_client_default(struct pps_device *pps, int event,
|
||||
void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
@@ -80,13 +88,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
|
||||
err = -EINVAL;
|
||||
goto pps_register_source_exit;
|
||||
}
|
||||
if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
|
||||
info->echo == NULL) {
|
||||
pr_err("%s: echo function is not defined\n",
|
||||
info->name);
|
||||
err = -EINVAL;
|
||||
goto pps_register_source_exit;
|
||||
}
|
||||
if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
|
||||
pr_err("%s: unspecified time format\n",
|
||||
info->name);
|
||||
@@ -108,6 +109,11 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
|
||||
pps->params.mode = default_params;
|
||||
pps->info = *info;
|
||||
|
||||
/* check for default echo function */
|
||||
if ((pps->info.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) &&
|
||||
pps->info.echo == NULL)
|
||||
pps->info.echo = pps_echo_client_default;
|
||||
|
||||
init_waitqueue_head(&pps->queue);
|
||||
spin_lock_init(&pps->lock);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user