Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
81bf58eb
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
81bf58eb
编写于
11月 08, 2011
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge branches 'regmap/irq' and 'regmap/cache' into regmap-next
上级
b973aa36
f8beab2b
50b776fc
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
361 addition
and
3 deletion
+361
-3
drivers/base/regmap/Kconfig
drivers/base/regmap/Kconfig
+3
-0
drivers/base/regmap/Makefile
drivers/base/regmap/Makefile
+1
-0
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+1
-0
drivers/base/regmap/regcache-lzo.c
drivers/base/regmap/regcache-lzo.c
+1
-1
drivers/base/regmap/regcache.c
drivers/base/regmap/regcache.c
+19
-0
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-irq.c
+284
-0
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+3
-1
include/linux/regmap.h
include/linux/regmap.h
+49
-1
未找到文件。
drivers/base/regmap/Kconfig
浏览文件 @
81bf58eb
...
@@ -13,3 +13,6 @@ config REGMAP_I2C
...
@@ -13,3 +13,6 @@ config REGMAP_I2C
config REGMAP_SPI
config REGMAP_SPI
tristate
tristate
config REGMAP_IRQ
bool
drivers/base/regmap/Makefile
浏览文件 @
81bf58eb
...
@@ -3,3 +3,4 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
...
@@ -3,3 +3,4 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
obj-$(CONFIG_DEBUG_FS)
+=
regmap-debugfs.o
obj-$(CONFIG_DEBUG_FS)
+=
regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C)
+=
regmap-i2c.o
obj-$(CONFIG_REGMAP_I2C)
+=
regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI)
+=
regmap-spi.o
obj-$(CONFIG_REGMAP_SPI)
+=
regmap-spi.o
obj-$(CONFIG_REGMAP_IRQ)
+=
regmap-irq.o
drivers/base/regmap/internal.h
浏览文件 @
81bf58eb
...
@@ -74,6 +74,7 @@ struct regmap {
...
@@ -74,6 +74,7 @@ struct regmap {
struct
reg_default
*
reg_defaults
;
struct
reg_default
*
reg_defaults
;
const
void
*
reg_defaults_raw
;
const
void
*
reg_defaults_raw
;
void
*
cache
;
void
*
cache
;
bool
cache_dirty
;
};
};
struct
regcache_ops
{
struct
regcache_ops
{
...
...
drivers/base/regmap/regcache-lzo.c
浏览文件 @
81bf58eb
...
@@ -354,7 +354,7 @@ static int regcache_lzo_sync(struct regmap *map)
...
@@ -354,7 +354,7 @@ static int regcache_lzo_sync(struct regmap *map)
}
}
struct
regcache_ops
regcache_lzo_ops
=
{
struct
regcache_ops
regcache_lzo_ops
=
{
.
type
=
REGCACHE_
LZO
,
.
type
=
REGCACHE_
COMPRESSED
,
.
name
=
"lzo"
,
.
name
=
"lzo"
,
.
init
=
regcache_lzo_init
,
.
init
=
regcache_lzo_init
,
.
exit
=
regcache_lzo_exit
,
.
exit
=
regcache_lzo_exit
,
...
...
drivers/base/regmap/regcache.c
浏览文件 @
81bf58eb
...
@@ -241,6 +241,8 @@ int regcache_sync(struct regmap *map)
...
@@ -241,6 +241,8 @@ int regcache_sync(struct regmap *map)
map
->
cache_ops
->
name
);
map
->
cache_ops
->
name
);
name
=
map
->
cache_ops
->
name
;
name
=
map
->
cache_ops
->
name
;
trace_regcache_sync
(
map
->
dev
,
name
,
"start"
);
trace_regcache_sync
(
map
->
dev
,
name
,
"start"
);
if
(
!
map
->
cache_dirty
)
goto
out
;
if
(
map
->
cache_ops
->
sync
)
{
if
(
map
->
cache_ops
->
sync
)
{
ret
=
map
->
cache_ops
->
sync
(
map
);
ret
=
map
->
cache_ops
->
sync
(
map
);
}
else
{
}
else
{
...
@@ -290,6 +292,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
...
@@ -290,6 +292,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
}
}
EXPORT_SYMBOL_GPL
(
regcache_cache_only
);
EXPORT_SYMBOL_GPL
(
regcache_cache_only
);
/**
* regcache_mark_dirty: Mark the register cache as dirty
*
* @map: map to mark
*
* Mark the register cache as dirty, for example due to the device
* having been powered down for suspend. If the cache is not marked
* as dirty then the cache sync will be suppressed.
*/
void
regcache_mark_dirty
(
struct
regmap
*
map
)
{
mutex_lock
(
&
map
->
lock
);
map
->
cache_dirty
=
true
;
mutex_unlock
(
&
map
->
lock
);
}
EXPORT_SYMBOL_GPL
(
regcache_mark_dirty
);
/**
/**
* regcache_cache_bypass: Put a register map into cache bypass mode
* regcache_cache_bypass: Put a register map into cache bypass mode
*
*
...
...
drivers/base/regmap/regmap-irq.c
0 → 100644
浏览文件 @
81bf58eb
/*
* regmap based irq_chip
*
* Copyright 2011 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/export.h>
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include "internal.h"
struct
regmap_irq_chip_data
{
struct
mutex
lock
;
struct
regmap
*
map
;
struct
regmap_irq_chip
*
chip
;
int
irq_base
;
void
*
status_reg_buf
;
unsigned
int
*
status_buf
;
unsigned
int
*
mask_buf
;
unsigned
int
*
mask_buf_def
;
};
static
inline
const
struct
regmap_irq
*
irq_to_regmap_irq
(
struct
regmap_irq_chip_data
*
data
,
int
irq
)
{
return
&
data
->
chip
->
irqs
[
irq
-
data
->
irq_base
];
}
static
void
regmap_irq_lock
(
struct
irq_data
*
data
)
{
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
mutex_lock
(
&
d
->
lock
);
}
static
void
regmap_irq_sync_unlock
(
struct
irq_data
*
data
)
{
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
int
i
,
ret
;
/*
* If there's been a change in the mask write it back to the
* hardware. We rely on the use of the regmap core cache to
* suppress pointless writes.
*/
for
(
i
=
0
;
i
<
d
->
chip
->
num_regs
;
i
++
)
{
ret
=
regmap_update_bits
(
d
->
map
,
d
->
chip
->
mask_base
+
i
,
d
->
mask_buf_def
[
i
],
d
->
mask_buf
[
i
]);
if
(
ret
!=
0
)
dev_err
(
d
->
map
->
dev
,
"Failed to sync masks in %x
\n
"
,
d
->
chip
->
mask_base
+
i
);
}
mutex_unlock
(
&
d
->
lock
);
}
static
void
regmap_irq_enable
(
struct
irq_data
*
data
)
{
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
const
struct
regmap_irq
*
irq_data
=
irq_to_regmap_irq
(
d
,
data
->
irq
);
d
->
mask_buf
[
irq_data
->
reg_offset
]
&=
~
irq_data
->
mask
;
}
static
void
regmap_irq_disable
(
struct
irq_data
*
data
)
{
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
const
struct
regmap_irq
*
irq_data
=
irq_to_regmap_irq
(
d
,
data
->
irq
);
d
->
mask_buf
[
irq_data
->
reg_offset
]
|=
irq_data
->
mask
;
}
static
struct
irq_chip
regmap_irq_chip
=
{
.
name
=
"regmap"
,
.
irq_bus_lock
=
regmap_irq_lock
,
.
irq_bus_sync_unlock
=
regmap_irq_sync_unlock
,
.
irq_disable
=
regmap_irq_disable
,
.
irq_enable
=
regmap_irq_enable
,
};
static
irqreturn_t
regmap_irq_thread
(
int
irq
,
void
*
d
)
{
struct
regmap_irq_chip_data
*
data
=
d
;
struct
regmap_irq_chip
*
chip
=
data
->
chip
;
struct
regmap
*
map
=
data
->
map
;
int
ret
,
i
;
u8
*
buf8
=
data
->
status_reg_buf
;
u16
*
buf16
=
data
->
status_reg_buf
;
u32
*
buf32
=
data
->
status_reg_buf
;
ret
=
regmap_bulk_read
(
map
,
chip
->
status_base
,
data
->
status_reg_buf
,
chip
->
num_regs
);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to read IRQ status: %d
\n
"
,
ret
);
return
IRQ_NONE
;
}
/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
* interrupt. We assume that typically few of the interrupts
* will fire simultaneously so don't worry about overhead from
* doing a write per register.
*/
for
(
i
=
0
;
i
<
data
->
chip
->
num_regs
;
i
++
)
{
switch
(
map
->
format
.
val_bytes
)
{
case
1
:
data
->
status_buf
[
i
]
=
buf8
[
i
];
break
;
case
2
:
data
->
status_buf
[
i
]
=
buf16
[
i
];
break
;
case
4
:
data
->
status_buf
[
i
]
=
buf32
[
i
];
break
;
default:
BUG
();
return
IRQ_NONE
;
}
data
->
status_buf
[
i
]
&=
~
data
->
mask_buf
[
i
];
if
(
data
->
status_buf
[
i
]
&&
chip
->
ack_base
)
{
ret
=
regmap_write
(
map
,
chip
->
ack_base
+
i
,
data
->
status_buf
[
i
]);
if
(
ret
!=
0
)
dev_err
(
map
->
dev
,
"Failed to ack 0x%x: %d
\n
"
,
chip
->
ack_base
+
i
,
ret
);
}
}
for
(
i
=
0
;
i
<
chip
->
num_irqs
;
i
++
)
{
if
(
data
->
status_buf
[
chip
->
irqs
[
i
].
reg_offset
]
&
chip
->
irqs
[
i
].
mask
)
{
handle_nested_irq
(
data
->
irq_base
+
i
);
}
}
return
IRQ_HANDLED
;
}
/**
* regmap_add_irq_chip(): Use standard regmap IRQ controller handling
*
* map: The regmap for the device.
* irq: The IRQ the device uses to signal interrupts
* irq_flags: The IRQF_ flags to use for the primary interrupt.
* chip: Configuration for the interrupt controller.
* data: Runtime data structure for the controller, allocated on success
*
* Returns 0 on success or an errno on failure.
*
* In order for this to be efficient the chip really should use a
* register cache. The chip driver is responsible for restoring the
* register values used by the IRQ controller over suspend and resume.
*/
int
regmap_add_irq_chip
(
struct
regmap
*
map
,
int
irq
,
int
irq_flags
,
int
irq_base
,
struct
regmap_irq_chip
*
chip
,
struct
regmap_irq_chip_data
**
data
)
{
struct
regmap_irq_chip_data
*
d
;
int
cur_irq
,
i
;
int
ret
=
-
ENOMEM
;
irq_base
=
irq_alloc_descs
(
irq_base
,
0
,
chip
->
num_irqs
,
0
);
if
(
irq_base
<
0
)
{
dev_warn
(
map
->
dev
,
"Failed to allocate IRQs: %d
\n
"
,
irq_base
);
return
irq_base
;
}
d
=
kzalloc
(
sizeof
(
*
d
),
GFP_KERNEL
);
if
(
!
d
)
return
-
ENOMEM
;
d
->
status_buf
=
kzalloc
(
sizeof
(
unsigned
int
)
*
chip
->
num_regs
,
GFP_KERNEL
);
if
(
!
d
->
status_buf
)
goto
err_alloc
;
d
->
status_reg_buf
=
kzalloc
(
map
->
format
.
val_bytes
*
chip
->
num_regs
,
GFP_KERNEL
);
if
(
!
d
->
status_reg_buf
)
goto
err_alloc
;
d
->
mask_buf
=
kzalloc
(
sizeof
(
unsigned
int
)
*
chip
->
num_regs
,
GFP_KERNEL
);
if
(
!
d
->
mask_buf
)
goto
err_alloc
;
d
->
mask_buf_def
=
kzalloc
(
sizeof
(
unsigned
int
)
*
chip
->
num_regs
,
GFP_KERNEL
);
if
(
!
d
->
mask_buf_def
)
goto
err_alloc
;
d
->
map
=
map
;
d
->
chip
=
chip
;
d
->
irq_base
=
irq_base
;
mutex_init
(
&
d
->
lock
);
for
(
i
=
0
;
i
<
chip
->
num_irqs
;
i
++
)
d
->
mask_buf_def
[
chip
->
irqs
[
i
].
reg_offset
]
|=
chip
->
irqs
[
i
].
mask
;
/* Mask all the interrupts by default */
for
(
i
=
0
;
i
<
chip
->
num_regs
;
i
++
)
{
d
->
mask_buf
[
i
]
=
d
->
mask_buf_def
[
i
];
ret
=
regmap_write
(
map
,
chip
->
mask_base
+
i
,
d
->
mask_buf
[
i
]);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to set masks in 0x%x: %d
\n
"
,
chip
->
mask_base
+
i
,
ret
);
goto
err_alloc
;
}
}
/* Register them with genirq */
for
(
cur_irq
=
irq_base
;
cur_irq
<
chip
->
num_irqs
+
irq_base
;
cur_irq
++
)
{
irq_set_chip_data
(
cur_irq
,
d
);
irq_set_chip_and_handler
(
cur_irq
,
&
regmap_irq_chip
,
handle_edge_irq
);
irq_set_nested_thread
(
cur_irq
,
1
);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags
(
cur_irq
,
IRQF_VALID
);
#else
irq_set_noprobe
(
cur_irq
);
#endif
}
ret
=
request_threaded_irq
(
irq
,
NULL
,
regmap_irq_thread
,
irq_flags
,
chip
->
name
,
d
);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to request IRQ %d: %d
\n
"
,
irq
,
ret
);
goto
err_alloc
;
}
return
0
;
err_alloc:
kfree
(
d
->
mask_buf_def
);
kfree
(
d
->
mask_buf
);
kfree
(
d
->
status_reg_buf
);
kfree
(
d
->
status_buf
);
kfree
(
d
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_add_irq_chip
);
/**
* regmap_del_irq_chip(): Stop interrupt handling for a regmap IRQ chip
*
* @irq: Primary IRQ for the device
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
*/
void
regmap_del_irq_chip
(
int
irq
,
struct
regmap_irq_chip_data
*
d
)
{
if
(
!
d
)
return
;
free_irq
(
irq
,
d
);
kfree
(
d
->
mask_buf_def
);
kfree
(
d
->
mask_buf
);
kfree
(
d
->
status_reg_buf
);
kfree
(
d
->
status_buf
);
kfree
(
d
);
}
EXPORT_SYMBOL_GPL
(
regmap_del_irq_chip
);
drivers/base/regmap/regmap.c
浏览文件 @
81bf58eb
...
@@ -306,9 +306,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
...
@@ -306,9 +306,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
ret
=
regcache_write
(
map
,
reg
,
val
);
ret
=
regcache_write
(
map
,
reg
,
val
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
return
ret
;
return
ret
;
if
(
map
->
cache_only
)
if
(
map
->
cache_only
)
{
map
->
cache_dirty
=
true
;
return
0
;
return
0
;
}
}
}
trace_regmap_reg_write
(
map
->
dev
,
reg
,
val
);
trace_regmap_reg_write
(
map
->
dev
,
reg
,
val
);
...
...
include/linux/regmap.h
浏览文件 @
81bf58eb
...
@@ -25,7 +25,7 @@ enum regcache_type {
...
@@ -25,7 +25,7 @@ enum regcache_type {
REGCACHE_NONE
,
REGCACHE_NONE
,
REGCACHE_INDEXED
,
REGCACHE_INDEXED
,
REGCACHE_RBTREE
,
REGCACHE_RBTREE
,
REGCACHE_
LZO
REGCACHE_
COMPRESSED
};
};
/**
/**
...
@@ -143,5 +143,53 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
...
@@ -143,5 +143,53 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
int
regcache_sync
(
struct
regmap
*
map
);
int
regcache_sync
(
struct
regmap
*
map
);
void
regcache_cache_only
(
struct
regmap
*
map
,
bool
enable
);
void
regcache_cache_only
(
struct
regmap
*
map
,
bool
enable
);
void
regcache_cache_bypass
(
struct
regmap
*
map
,
bool
enable
);
void
regcache_cache_bypass
(
struct
regmap
*
map
,
bool
enable
);
void
regcache_mark_dirty
(
struct
regmap
*
map
);
/**
* Description of an IRQ for the generic regmap irq_chip.
*
* @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register.
*/
struct
regmap_irq
{
unsigned
int
reg_offset
;
unsigned
int
mask
;
};
/**
* Description of a generic regmap irq_chip. This is not intended to
* handle every possible interrupt controller, but it should handle a
* substantial proportion of those that are found in the wild.
*
* @name: Descriptive name for IRQ controller.
*
* @status_base: Base status register address.
* @mask_base: Base mask register address.
* @ack_base: Base ack address. If zero then the chip is clear on read.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
* assigned based on the index in the array of the interrupt.
* @num_irqs: Number of descriptors.
*/
struct
regmap_irq_chip
{
const
char
*
name
;
unsigned
int
status_base
;
unsigned
int
mask_base
;
unsigned
int
ack_base
;
int
num_regs
;
const
struct
regmap_irq
*
irqs
;
int
num_irqs
;
};
struct
regmap_irq_chip_data
;
int
regmap_add_irq_chip
(
struct
regmap
*
map
,
int
irq
,
int
irq_flags
,
int
irq_base
,
struct
regmap_irq_chip
*
chip
,
struct
regmap_irq_chip_data
**
data
);
void
regmap_del_irq_chip
(
int
irq
,
struct
regmap_irq_chip_data
*
data
);
#endif
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录