上篇講了Linux clock驅(qū)動(dòng),今天說(shuō)說(shuō)Linux的reset驅(qū)動(dòng)。
時(shí)鐘和復(fù)位是兩個(gè)不同的驅(qū)動(dòng),但通常都是由負(fù)責(zé)clock驅(qū)動(dòng)的人,把reset驅(qū)動(dòng)完成。同樣,reset驅(qū)動(dòng)也是由芯片廠商去完成的。
Linux reset子系統(tǒng)
reset子系統(tǒng)非常簡(jiǎn)單,與clock子系統(tǒng)非常類似,但在驅(qū)動(dòng)實(shí)現(xiàn)上,reset驅(qū)動(dòng)更簡(jiǎn)單。
因?yàn)閏lock驅(qū)動(dòng)主要是時(shí)鐘的實(shí)現(xiàn),涉及到固定時(shí)鐘、分頻、門控等一些時(shí)鐘的分級(jí)關(guān)系,需要弄清楚時(shí)鐘樹(shù)里每個(gè)時(shí)鐘的關(guān)系。
而reset驅(qū)動(dòng)有點(diǎn)相當(dāng)于clock驅(qū)動(dòng)的門控,它只有復(fù)位和解復(fù)位兩個(gè)功能。
類似于clock子系統(tǒng),reset子系統(tǒng)也分為了consumer
和provider
,結(jié)構(gòu)體關(guān)系如下:
consumer :
reset API接口的使用者,內(nèi)核提供了統(tǒng)一的reset接口:
devm_reset_control_get(struct device *dev, const char *id)//獲取reset句柄
reset_control_deassert(struct reset_control *rstc)//解復(fù)位
reset_control_assert(struct reset_control *rstc)//復(fù)位
reset_control_reset(struct reset_control *rstc)//先復(fù)位,延遲一會(huì),然后解復(fù)位
struct reset_control結(jié)構(gòu)體表示一個(gè)reset句柄,驅(qū)動(dòng)中使用reset API,需要先獲取reset句柄
provider :
reset提供者,即reset驅(qū)動(dòng)。struct reset_controller_dev
結(jié)構(gòu)體代表一個(gè)reset
控制器,內(nèi)部包含了reset操作函數(shù)集合struct reset_control_ops
,注冊(cè)reset驅(qū)動(dòng)時(shí),需要分配一個(gè)struct reset_controller_dev結(jié)構(gòu)體,然后填充成員,最后將該結(jié)構(gòu)體注冊(cè)。
struct reset_controller_dev{
const struct reset_control_ops *ops;//復(fù)位控制操作函數(shù)
struct list_head list;//全局鏈表,復(fù)位控制器注冊(cè)后掛載到全局鏈表
struct list_head reset_control_head;//各個(gè)模塊復(fù)位的鏈表頭
struct device *dev;
int of_reset_n_cells;//dts中引用時(shí),需要幾個(gè)參數(shù)
//通過(guò)dts引用的參數(shù),解析復(fù)位控制器中相應(yīng)的參數(shù)
int (*of_xlate)(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec);
unsigned int nr_resets;//復(fù)位設(shè)備個(gè)數(shù)
}
struct reset_control_ops{
int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);//復(fù)位+解復(fù)位
int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);//復(fù)位
int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);//解復(fù)位
int (*status)(struct reset_controller_dev *rcdev, unsigned long id);//復(fù)位狀態(tài)查詢
}
reset復(fù)位API說(shuō)明
devm_reset_control_get
struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
- 作用 :獲取相應(yīng)的reset句柄
- 參數(shù) :
- dev:指向申請(qǐng)reset資源的設(shè)備句柄
- id:指向要申請(qǐng)的reset資源名(字符串),可以為NULL
- 返回 :
- 成功:返回reset句柄
- 失敗:返回NULL
reset_control_deassert
int reset_control_deassert(struct reset_control *rstc)
- 作用 :對(duì)傳入的reset資源進(jìn)行解復(fù)位操作
- 參數(shù) :
- rstc:指向申請(qǐng)reset資源的設(shè)備句柄
- 返回 :
- 成功:返回0
- 失?。悍祷劐e(cuò)誤碼
reset_control_assert
int reset_control_assert(struct reset_control *rstc)
- 作用 :對(duì)傳入的reset資源進(jìn)行復(fù)位操作。
參數(shù)和返回值與reset_control_deassert
相同
reset_control_reset
int reset_control_reset(struct reset_control *rstc)
- 作用:對(duì)傳入的reset資源先進(jìn)行復(fù)位操作,然后等待5us,再進(jìn)行解復(fù)位操作。
- 相當(dāng)于執(zhí)行了一遍
reset_control_assert
后,然后delay一會(huì),再調(diào)用reset_control_deassert
reset API使用示例
基本步驟:
1、調(diào)用devm_reset_control_get()
獲取reset句柄
2、調(diào)用reset_control_assert()
進(jìn)行復(fù)位操作
3、調(diào)用reset_control_deassert()
進(jìn)行解復(fù)位操作
static int xx_probe(struct platform_device *pdev)
{
struct device_node* np = pdev-?>dev.of_node;
......
/* 1、獲取reset句柄 */
host-?>rstc = devm_reset_control_get(&pdev-?>dev, np-?>name);
if (IS_ERR(host-?>rstc)) {
dev_err(&pdev-?>dev, "No reset controller specified\\n");
return PTR_ERR(host-?>rstc);
}
if (host-?>rstc) {
/* 2、復(fù)位 */
ret = reset_control_assert(host-?>rstc);
if (ret) {
dev_err(&pdev-?>dev, "unable to reset_control_assert\\n");
return ret;
}
udelay(1);
/* 3、解復(fù)位 */
ret = reset_control_deassert(host-?>rstc);
if (ret) {
dev_err(&pdev-?>dev, "unable to reset_control_deassert\\n");
return ret;
}
}
......
}
reset驅(qū)動(dòng)實(shí)例
類似于clock驅(qū)動(dòng),reset驅(qū)動(dòng)也是編進(jìn)內(nèi)核的,在Linux啟動(dòng)時(shí),完成reset驅(qū)動(dòng)的加載。
設(shè)備樹(shù)
reset:reset-controller{
compatible = "xx,xx-reset";
reg = 0x0 0xc0000000 0x0 0x1000?>;
#reset-cells = 1?>;
};
上述是一個(gè)reset控制器的節(jié)點(diǎn),0xc0000000
是寄存器基址,0x1000
是映射大小。 #reset-cells
代表引用該reset時(shí)需要的cells個(gè)數(shù)。
例如,#reset-cells = <1>;
則正確引用為:
mmc:mmc@0x12345678{
......
resets = &reset 0?>;//0代表reset設(shè)備id,id是自定義的,但是不能超過(guò)reset驅(qū)動(dòng)中指定的設(shè)備個(gè)數(shù)
......
};
驅(qū)動(dòng)編寫
reset驅(qū)動(dòng)編寫的基本步驟:
1、實(shí)現(xiàn)struct reset_control_ops
結(jié)構(gòu)體中的.reset
、.assert
、.deassert
、.status
函數(shù)
2、分配struct reset_controller_dev
結(jié)構(gòu)體,填充ops
、owner
、nr_resets
等成員內(nèi)容
3、調(diào)用reset_controller_register
函數(shù)注冊(cè)reset設(shè)備
以下是從實(shí)際項(xiàng)目中分離出來(lái)的reset驅(qū)動(dòng)代碼:
#include
#include
#include
#include
#include
#include
// 自定義芯片廠的結(jié)構(gòu)體,保存寄存器基址等信息
struct xx_reset{
struct reset_controller_dev rcdev;
void __iomem *base;
//......
};
static int xx_reset(struct reset_controller_dev *rcdev, unsigned long id)
{
//操作寄存器:先復(fù)位,延遲一會(huì),然后解復(fù)位
return 0;
}
static int xx_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
//操作寄存器:復(fù)位
return 0;
}
static int xx_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
//操作寄存器:解復(fù)位
return 0;
}
static int xx_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
{
//操作寄存器:獲取復(fù)位狀態(tài)
return 0;
}
static struct reset_control_ops xx_reset_ops = {
.rest = xx_rest,
.assert = xx_reset_asser,
.deassert = xx_reset_deassert,
.status = xx_rest_status,
};
static int xx_reset_probe(struct platform_device *pdev)
{
struct xx_reset *xx_reset;
struct resource *res;
xx_reset = devm_kzalloc(&pdev-?>dev, sizeof(*xx_reset), GFP_KERNEL);
if (!xx_reset)
return -ENOMEM;
platform_set_drvdata(pdev, xx_reset);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xx_reset-?>base = devm_ioremap_resource(&pdev-?>dev, res);//映射寄存器基址
if (IS_ERR(xx_reset-?>base))
return PTR_ERR(xx_reset-?>base);
xx_reset-?>rcdev.ops = &xx_reset_ops;//reset_ops操作函數(shù)集合
xx_reset-?>rcdev.owner = THIS_MODULE;
xx_reset-?>rcdev.of_node = pdev-?>dev.of_node;
xx_reset-?>rcdev.of_reset_n_cells = 1;
xx_reset-?>rcdev.nr_resets = BITS_PER_LONG;//reset設(shè)備個(gè)數(shù)
return reset_controller_register(&xx_reset-?>rcdev);//注冊(cè)reset controller
}
static int xx_reset_remove(struct platform_device *pdev)
{
struct xx_reste *xx_reset = platform_get_drvdata(pdev);
reset_controller_unregister(&xx_reset-?>rcdev);
return 0;
}
static const struct of_device_id ak_reset_of_match[]={
{.compatible = "xx,xx-reset"},
{},
};
MODULE_DEVICE_TABLE(of, xx_reset_of_match);
static struct platform_driver xx_reset_driver = {
.probe = xx_reset_probe,
.remove = xx_reset_remove,
.driver = {
.name = "xx-reset",
.of_match_table = ak_reset_of_match,
},
};
module_platorm_driver(xx_reset_driver);
MODULE_LICENSE("GPL");
MODULE_DESCPRIPTION("xx reset controller driver");
MODULE_AUTHOR("xx Microelectronic");
MODULE_VERSION("v1.0.00");